IB_DESIGNABLE, IBInspectable - Konstruktor interfejsów nie aktualizuje się

91

Mam następujący zestaw kodów:

CustomView.h

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface CustomView : UIView

@property (nonatomic) IBInspectable UIColor *borderColor;
@property (nonatomic) IBInspectable CGFloat borderWidth;
@property (nonatomic) IBInspectable CGFloat cornerRadius;

@end

CustomView.m

#import "CustomView.h"

@implementation CustomView

- (void)setBorderColor:(UIColor *)borderColor {
    _borderColor = borderColor;
    self.layer.borderColor = borderColor.CGColor;
}

- (void)setBorderWidth:(CGFloat)borderWidth {
    _borderWidth = borderWidth;
    self.layer.borderWidth = borderWidth;
}

- (void)setCornerRadius:(CGFloat)cornerRadius {
    _cornerRadius = cornerRadius;
    self.layer.cornerRadius = cornerRadius;
}

@end

(Dla odniesienia w języku Swift ten problem występował również w kodzie Swift)

CustomView.swift

@IBDesignable
class CustomView : UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    @IBInspectable var borderColor : UIColor = UIColor.clearColor() {
        didSet {
            self.layer.borderColor = borderColor.CGColor
        }
    }

    @IBInspectable var borderWidth : CGFloat = 0.0 {
        didSet {
            self.layer.borderWidth = borderWidth
        }
    }

    @IBInspectable var cornerRadius : CGFloat = 0.0 {
        didSet {
            self.layer.cornerRadius = cornerRadius
        }
    }
}

Dodałem UIViewdo kontrolera widoku w scenorysie i ustawiłem jego podklasę na CustomView.

wprowadź opis obrazu tutaj

Spowoduje to dodanie wiersza „Designables”. Utknął na „Aktualizacji”, a podpowiedź mówi „Oczekiwanie na zbudowanie celu”. Ten status nigdy się nie zmienia.

Kiedy przejdę do inspekcji atrybutów, mogę ustawić następujące IBInspectablewłaściwości:

wprowadź opis obrazu tutaj

Po ustawieniu pojawiają się również w „Atrybutach środowiska wykonawczego zdefiniowanych przez użytkownika”:

wprowadź opis obrazu tutaj

Jednak status „Designables” nigdy nie wykracza poza „Updating” z wciąż tą samą wskazówką (próbowałem budować Cmd + B kilka razy, nic się nie zmienia).

Ponadto podczas ustawiania IBInspectablewłaściwości otrzymuję ostrzeżenie o każdej z nich:

IBDesignables - Ignorowanie atrybutu środowiska wykonawczego zdefiniowanego przez użytkownika dla ścieżki klucza „borderColor” w wystąpieniu „UIView” ... ta klasa nie jest zgodna z kodowaniem klucz-wartość dla klucza borderColor.

Zrzut ekranu z wygenerowanymi ostrzeżeniami:

wprowadź opis obrazu tutaj


Znam problemy związane z kodowaniem klucz-wartość i ogólnie wiem, jak je rozwiązać ... ale nie rozumiem, jak rozwiązać ten problem tutaj. Według inspektora tożsamości widoku jest to „Widok niestandardowy” (a nie zwykły „UIView”, który nie ma tych właściwości). A gdyby widok nie był „Widokiem niestandardowym”, te dające się zaprojektować właściwości nie pojawiałyby się w Inspektorze atrybutów, prawda? Ale kiedy Interface Builder próbuje zastosować te atrybuty do widoku, wraca do myślenia, że ​​klasą widoku jest „UIView” i nie może zastosować atrybutów.

Jakaś pomoc? Daj mi znać, jeśli pominąłem kilka ważnych szczegółów, ale ze względu na to, co jest warte, dokładnie postępowałem zgodnie z tym samouczkiem (poza ObjC vs Swift). Warto również zauważyć, że śledziłem ten samouczek dokładnie na innej maszynie i działał jak urok (zamierzałem napisać ten post wczoraj wieczorem, ale komputer, na którym byłem wtedy, nie miał tego problemu).


Na podstawie komentarzy zasugerowano, że być może .mplik nie jest dołączony i to może być przyczyną problemu. Myślałem, że na pewno zrobię wszystko, co w mojej mocy, aby ten scenariusz miał miejsce, ale i tak sprawdziłem.

wprowadź opis obrazu tutaj

Kiedy po raz pierwszy zacząłem to robić, zdawałem sobie sprawę, że te IB_DESIGNABLEzajęcia muszą być częścią innej UIKitstruktury. Na tym pierwszym zrzucie ekranu widać, że skonfigurowałem strukturę „CustomViews”, która ma jedną klasę CustomView. Zobaczysz tutaj również, że utworzyłem również plik OtherView, który jest identyczny z tym CustomView, że nie znajduje się w oddzielnym frameworku. Jednak identyczny problem występuje w scenorysie między obiema klasami.

Tutaj mamy zrzut ekranu wskazujący, że CustomView.mjest dołączony do zbudowania z CustomViewsframeworkiem:

wprowadź opis obrazu tutaj

Tymczasem poniższy zrzut ekranu wskazuje na kilka rzeczy:

  • CustomViews.framework jest odpowiednio uwzględniony w głównym projekcie.
  • OtherView.mjest również dołączany jako źródło kompilacji, więc nawet jeśli coś jest nie tak CustomView, OtherViewpowinno działać, jednak generuje identyczne błędy.
  • Main.storyboardi LaunchScreen.xibsą wyświetlane jako czerwone. Nie mam pojęcia dlaczego i nie mam najmniejszego pojęcia, dlaczego LaunchScreen.xibpowinienem (nie dotykałem tego pliku), chociaż mogę powiedzieć, że po obejrzeniu innych projektów, Main.storyboardrównież pojawia się na czerwono dla tych projektów, a ja nic nie robić z IB_DESIGNABLElub IBInspectabletam.

wprowadź opis obrazu tutaj


Próbowałem i próbowałem to teraz kilka razy. Działa za każdym razem na moim komputerze w domu - nie mogę odtworzyć problemu opisanego w tym pytaniu w domu. W pracy to nigdy nie działa. Problem opisany w tym pytaniu zdarza się za każdym razem.

Oba komputery to Mac Minis zakupione nowe w tym roku (nie nowe modele, model z końca 2012 roku). Oba komputery działają pod kontrolą systemu OS X Yosemite 10.10. Na obu komputerach działa Xcode w wersji 6.1. W domu kompilacja to (6A1052d). Dziś rano mogę potwierdzić, że na obu komputerach działają identyczne kompilacje Xcode.

Inni zasugerowali mi, że może to być zła pamięć RAM. Wydaje mi się to naciągane. Wielokrotnie restartowałem projekt, wielokrotnie restartowałem komputer. Wydaje mi się, że gdyby na komputerze mającym około 6 miesięcy była zła pamięć RAM, zobaczyłbym inne problemy i że ten problem byłby mniej spójny. Ale ten właśnie problem utrzymuje się pomimo wielokrotnego restartowania całego projektu od zera i pełnych restartów na komputerze.


Warto zauważyć, że jeśli faktycznie skompiluję i uruchomię ten projekt, niestandardowy widok z IBInspectablewłaściwościami faktycznie wyświetla się tak, jak oczekuję, że wyświetli go scenorys. Wyobrażam sobie, że tak by się stało nawet bez dyrektyw IB_DESIGNABLEi IBInspectable, ponieważ są one tworzone jako atrybuty środowiska wykonawczego zdefiniowane przez użytkownika.

nhgrif
źródło
Cóż, to był tylko pomysł. Usunąłem CustomView.m z miejsca docelowego, a następnie otrzymałem podobne ostrzeżenia podczas uruchamiania aplikacji.
Martin R
Wydaje się, że to prawdziwy gremlin, biorąc pod uwagę twoje porównanie do pozornie identycznej maszyny (która w jakiś sposób się różni). Czy próbowałeś publikować posty na devforums? Wygląda na to, że lecisz na ślepo bez dodatkowych informacji, a twój proces wydaje się rozsądny i racjonalny. Ostrzeżenie „kompilacja” może nie oznaczać zbyt wiele, ponieważ Xcode jest pełen wprowadzających w błąd komunikatów o błędach. Jeśli chodzi o kopnięcia, wypróbowałeś Editor -> „debuguj wybrany widok”, prawda? (Prawdopodobnie nie zadziała, ale warto sprawdzić poczytalność). Czy cokolwiek pojawia się w aplikacji konsoli (logowania)?
Chris Conover
Mam ten sam problem. Kopalnie z pojedynczym plikiem xib zawierającym IB_DESIGNABLE. Jednak sprawdzając moją konfigurację, mam już włączone automatyczne odświeżanie i próbowałem teraz odświeżyć ręcznie, najpierw wyczyścić dane pochodne itp. Jak dotąd nic nie działało. Dziwne jest to, że ten element sterujący działał dobrze, a potem się zatrzymał. I nie sądzę, żebym zmienił kod w międzyczasie. Zwariowany.
drekka
Pokazał ostrzeżenia jak powyżej. Utworzyłem teraz drugą klasę z kodem skopiowanym z pierwotnego projektu IB. Ta klasa działa doskonale, a kiedy wróciłem do pierwotnej niepracującej klasy, teraz działa dobrze. Z tego doszedłem do wniosku, że gdzieś istnieje pamięć podręczna (nie w danych pochodnych), która nie jest czyszczona, dopóki oryginalny projekt ib nie zostanie zamieniony na inny, który można zaprojektować. Zmiana na UIView nie powoduje wyczyszczenia tej pamięci podręcznej. Tylko kolejny ib do zaprojektowania. Idź rysunek :-)
drekka

Odpowiedzi:

75

Opierając się na sugestii Chrisco, aby debugować wybrany widok (co już zrobiłem, ale postanowiłem spróbować ponownie), zauważyłem kilka innych opcji na dole menu Edytor.

  • Automatycznie odświeżaj widoki
  • Odśwież wszystkie widoki

Kliknąłem „Odśwież wszystkie widoki” i po zastanowieniu się przez Xcode nagle scenorys wyświetlał mój widok zgodnie z oczekiwaniami (prawidłowo stosując moje IBInspectablewłaściwości).

wprowadź opis obrazu tutaj

Następnie ponownie przeszedłem przez cały proces, aby potwierdzić, że jest to rozwiązanie.

I stworzył nową klasę ThirdView. Ta klasa jest znowu identyczna z innymi. Zmieniłem klasę widoku na ThirdViewi tym razem otrzymałem coś nieco innego:

wprowadź opis obrazu tutaj

Kliknięcie „Pokaż” do ostrzeżeń:

wprowadź opis obrazu tutaj

Tym razem nowy:

Używanie klasy UIView dla obiektu z klasą niestandardową, ponieważ klasa ThirdView nie istnieje.

To naprawdę nie jest bardziej pomocne niż to, co już istniało. Dodatkowo, teraz pozostałe trzy ostrzeżenia podwoiły się do 6 dziwnie.

W każdym razie, jeśli ponownie kliknę „Odśwież wszystkie widoki” z menu rozwijanego Edytora, wszystkie błędy znikną i ponownie widok zostanie poprawnie wyświetlony.

Jednak do tego momentu wszystko, co robiłem, było rzeczami, których nigdy nie majstrowałem w domu. W domu po prostu działało. Więc włączyłem "Automatyczne odświeżanie widoków" i stworzyłem "FourthView" do przetestowania - po raz kolejny identyczny z trzema pierwszymi.

Po zmianie klasy widoku na „FourthView” etykieta designables mówiła na krótką chwilę „Aktualizowanie”, po czym w końcu powiedziała „Aktualne”:

wprowadź opis obrazu tutaj

Więc sprawdziłem komputer w domu. Na komputerze, który zawsze działał, włączono opcję „Automatyczne odświeżanie widoków”. Został wyłączony na komputerze, który nie był. Nie pamiętam, bym kiedykolwiek dotykał tej opcji menu. Nie mogę nawet powiedzieć na pewno, czy istniał przed Xcode 6. Ale ta opcja robi różnicę.


TL; DR, jeśli masz ten sam problem opisany w pytaniu, upewnij się, że opcja „Automatycznie odświeżaj widoki” jest włączona (lub ręcznie „Odśwież wszystkie widoki”, gdy potrzebujesz aktualizacji w IB):

wprowadź opis obrazu tutaj

nhgrif
źródło
2
Właściwie szukałem, jak go wyłączyć, ponieważ renderuje się w tle, dzięki czemu starsze MacBooki są naprawdę wolne. Dzięki!
Departamento B
Może to rozwiązać tymczasowo, ale sprawdź odpowiedź od @ Martin-Gilles Lavoie
Ashley Mills
22

Mam jeszcze kilka szczegółów, które mogą spowodować, że Twoje klasy IBDesignable nie zostaną załadowane.

Wybierz problematyczny scenorys / XIB, w którym powinny być wyświetlane niestandardowe widoki.

W obszarze nawigatora przejdź do Nawigatora raportów w obszarze roboczym / projekcie XCode.

W menu Edytora XCode naciśnij (jak wspomniał nhgrif) opcję „Odśwież wszystkie widoki”. To spowoduje, że IB uruchomi kompilację dla całej masy rzeczy, których, jestem pewien, nie spodziewałbyś się.

W Nawigatorze raportów kliknij „Według grupy”, aby przefiltrować zawartość i zajrzyj do sekcji „Konstruktor interfejsu”. Zobaczysz, że w celu załadowania niestandardowego frameworka widoków IBDesignable skompiluje WIELE rzeczy. Jeśli którykolwiek z tych celów NIE kompiluje się, na przykład (być może przestarzałe) cele testów jednostkowych (nawet jeśli są całkowicie niezwiązane z kodem, który ładuje te widoki lub scenorys), IB nie powiedzie się podczas ładowania biblioteki dll.

W moim przypadku IB próbował skompilować 8 celów, w tym 4, w których testy jednostkowe nie były aktualizowane od czasu ostatnich zmian refaktoryzacji, nad którymi pracowaliśmy.

Większość zmian / poprawek kodu, które zrobiłem, aby IB prawidłowo ładował i wyświetlał moje niestandardowe widoki, które nie były powiązane lub nawet połączone z tymi klasami, ani nigdy nie ładowałby storyboardu podczas wykonywania tych testów jednostkowych. Jednak IB miał zależność od kompilowania całego obszaru roboczego, aby to działało.

Martin-Gilles Lavoie
źródło
Hej, jak więc powstrzymać IB przed próbą ładowania i wyświetlania widoków niezwiązanych z tymi klasami lub z nimi powiązanych?
HannahCarney
Zakładam, że ma to związek z zależnościami nagłówka. Niezależnie od tego, czy możliwe do zaprojektowania klasy stykają się z innymi klasami, w momencie, gdy zostanie wyświetlony nagłówek, zbuduje on te powiązane implementacje. Apple bawi się kodem źródłowym wykresu zależności w XC7GM, który całkowicie zawodzi w naszym projekcie, ponieważ XCode ulega awarii podczas tworzenia wykresu. Następujące 7.1 betas nie wykazują problemu. Nasz zautomatyzowany system kompilacji nadal jest zależny od wersji 6.4, więc nie badaliśmy, jak dalej rozwiązać ten problem w XC6.4. Będziemy przeskakiwać prosto do 7,1GM.
Martin-Gilles Lavoie
Jeśli masz wiele celów / projektów, to jest to absolutnie właściwa odpowiedź i naprawdę rozwiązuje problem - WSZYSTKIE cele muszą zostać zbudowane bezproblemowo, nawet nie wiedziałem, że w nawigatorze raportów jest sekcja „Interface Builder”! Wszystkie inne odpowiedzi, które widziałem, to w zasadzie dużo machania rękami, które mogą to tymczasowo naprawić, ale to jest ostateczne rozwiązanie. Dobra robota.
Ashley Mills
3
Tak więc, zgodnie z tym, możemy wywnioskować, że atrybut IB_DESIGNABLE to totalne gówno i strata czasu. Po prostu unikaj używania tego.
m8labs
IB_DESIGNABLE nie ma nic wspólnego z problemem i rozwiązaniem wymienionym powyżej. To po prostu flaga NIE-OP dla IB, aby dostrzec przydatne rzeczy. Musisz tylko utrzymywać czysty dom.
Martin-Gilles Lavoie
22

Szybka wskazówka dla każdego, kto ma ten problem: pamiętaj, aby określić typ zmiennej.

// Doesn't show up in IB
@IBInspectable var includeLeftSection = true

// Shows now that it knows the type
@IBInspectable var includeLeftSection : Bool = true
GoldenJoe
źródło
6

Miałem to samo ostrzeżenie Ignoring user defined runtime attribute for key path ..Otrzymałem chociaż jestem absolutnie pewien, że nie zrobiłem nic złego w mojej niestandardowej klasie widoku IBDesignable.

Okazało się, że w moim przypadku ma to związek z pamięcią podręczną Xcode.

rm -rf ~/Library/Developer/Xcode/DerivedData/*

Oczyść DerivedDatai ostrzeżenie zniknęło.

samwize
źródło
1
Skrót w XCode do osiągnięcia tego samego wyniku: ⌘⇧K
Mojo66
@ Mojo66 Uważam, że Clean Build różni się od czyszczenia folderu DerivedData. Oczywiście, czasami czysta kompilacja jest wystarczająco dobra, aby rozwiązać pewne problemy z buforowaniem Xcode.
samwize
@ Mojo66 prawdopodobnie miałeś na myśli ⌘⌥⇧K (cmd + alt + shift + K)
tzaloga
5

O ile ktoś inny napotka błąd, klasa IB Designables nie istnieje, z tego samego powodu co ja. Najlepsza odpowiedź nie była moim problemem ... ale tutaj jest nieco powiązany problem ...

W kodzie źródłowym tablicy scenariuszy ukryta jest właściwość o nazwie customModule.

Na przykład miałem klasę o nazwie ForwardArrow w oddzielnym frameworku, który przypadkowo dodałem do mojego głównego celu.

Więc XML dla niektórych widoków zakończył się jako customClass = "ForwardArrow" customModule = "MainTargetNameWasHere"

Kiedy usunąłem je z głównego celu w kompilacji, storyboard nie zaktualizował MainTargetNameWasHere do CustomViews, czyli frameworka, w którym się znajdował i zaczął podawać, że żadna klasa nie znalazła błędu.

Więc TLDR; Upewnij się, że jeśli Twój IBDesignable znajduje się w innym frameworku, atrybut xml customModule w Twojej planszy scenariuszy ma odpowiednią wartość. A jeśli go tam w ogóle nie ma, dodaj go.

Przykład z mojego źródła:

<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="MUG-jc-2Ml" customClass="ForwardArrow" customModule="CustomViews">
Dave Thomas
źródło
1
O cholera, to doprowadzało mnie do szału na jeden dzień. Co za paskudny mały błąd.
GoldenJoe
5

Jako mój przykład użyłem CheckboxButton przez pod, a grafika pola wyboru nigdy nie pojawia się w scenorysie, podczas gdy mam te same problemy opisane w pytaniu tutaj:

ostrzeżenie: IB Designables: Używanie klasy UIView dla obiektu z klasą niestandardową, ponieważ klasa CheckboxButton nie istnieje

i

ostrzeżenie: IB Designables: Ignorowanie zdefiniowanego przez użytkownika atrybutu wykonawczego ścieżki klucza „checkColor” w instancji „UIView”. Uderzenie w wyjątek podczas próby ustawienia jego wartości: [setValue: forUndefinedKey:]: ta klasa nie jest zgodna z kodowaniem wartości klucza dla klucza checkColor.

Sposobem na rozwiązanie mojego problemu było podanie do modułu nazwy CheckboxButton jak poniżej:

Uwaga: należy zamienić CheckboxButton na dowolną nazwę modułu, którego używasz.

Nawet Cheng
źródło
4

Osobiście rozwiązałem ten problem, używając przycisku „-”, aby usunąć zawartość z mojego inspektora tożsamości. Kiedy usuwasz klasy niestandardowe, zmieniasz zawartość w IB, a następnie dodajesz nową klasę niestandardową, elementy do zaprojektowania w inspektorze tożsamości nie są usuwane i spowodowało to wystąpienie tego błędu. Po prostu usuń wszystko i odbuduj.wprowadź opis obrazu tutaj

HannahCarney
źródło
Zrobiłem dokładnie to, co powiedziałeś, i to rozwiązało mój problem. Wszystkie przedstawione tu poprzednie rozwiązania nie sprawdziły się. Wielkie dzięki. ; o)
XLE_22
@ XLE_22 czasami to odpowiedzi, na które nikt nie patrzy, rozwiązują problem, co? :)
HannahCarney
Wystąpił problem polegający na zmianie nazwy właściwości IBInspectable na kilku moich xib. Po wykonaniu tej czynności otrzymałem mnóstwo ostrzeżeń informujących mnie, że XCode nie może znaleźć właściwości, której nazwa została zmieniona. Usunięcie mienia z inspektora tożsamości rozwiązało mój problem.
WBuck
1

Wiem, że na to odpowiedź, ale oto jeszcze jedno doświadczenie.

Miałem problemy niezwiązane z tym problemem, ale w trakcie tego procesu usunąłem @IBInspectable z zmiennych w mojej klasie i skasowałem atrybuty z inspektora tożsamości (alt-apple-3).

Po naprawieniu problemu (kodu) z komponentem odświeżyłem wszystko mnóstwo razy, ale nadal nie ma atrybutów w inspektorze tożsamości.

W końcu zauważyłem, że wrócili, ale tylko w inspektorze atrybutów (alt-apple-4) . Jak tylko dodałem do nich wartości, pojawili się ponownie w inspektorze tożsamości

Gordon Dove
źródło
1

Powyższa odpowiedź Dave'a Thomasa dała mi (odwrotne) rozwiązanie, podczas gdy inne nie (Dane pochodne, Edytor> Odśwież), ale ze względu na przejrzystość na wypadek, gdyby ludzie nie byli pewni, gdzie edytować XML ... nie trzeba!

  1. W pliku storyboardu wybierz kłopotliwy widok
  2. Na prawym pasku bocznym wybierz zakładkę Identity Inspector (trzecia opcja od lewej).
  3. Będziesz mieć swoją klasę niestandardową, która powinna już być ustawiona, i plik Module. Dla mnie to było puste i otrzymywałem te same błędy co OP. I ustawić Moduledo mojego nazwa projektu i BAM - zaczęło działać po przebudowie!
whycodewhyyyy
źródło
0

Właśnie przejrzałem dzwonek w sprawie tego problemu. Próbowałem wszystkich wymienionych tutaj i innych rzeczy bez powodzenia. Jest to scenorys, który działał dobrze przez zawsze i nagle przestał działać z problemem „Ignorowanie atrybutu środowiska wykonawczego zdefiniowanego przez użytkownika ...”.

Z jakiegoś powodu usunięcie tego kodu z jednego z moich IBDesignable naprawiło to:

-(void)viewDidLoad {
    self.clipsToBounds = YES;
}

usunięcie tego spowodowało, że wszystkie ostrzeżenia zniknęły, nawet w innych obiektach IBDesignable. Nie mam pojęcia, dlaczego ten jeden krok to naprawił, ale może pomoże też komuś innemu.

IMFletcher
źródło
3
brakuje ci wezwania na kolację
RolandasR
0

Miałem ten sam problem i musiałem zmienić cornerRadius i BorderWidth na String, a następnie rzucić go na CGFloat, było to jedyne rozwiązanie dla mnie, aby móc zmienić wartości i zobaczyć zmiany w konstruktorze interfejsu.

@IBInspectable var borderColor: UIColor? {
    didSet {
        layer.borderColor = borderColor!.CGColor
    }
}

@IBInspectable var borderWidth: String? {
    didSet {
        layer.borderWidth = CGFloat(Int(borderWidth!) ?? 0)
    }
}

@IBInspectable var cornerRadius: String? {
    didSet {
        layer.cornerRadius = CGFloat(Int(cornerRadius!) ?? 0)
        layer.masksToBounds = layer.cornerRadius > 0
    }
}
Chuy47
źródło
Myślę, że IBInspectable może robić tylko niektóre typy, więc może musiałbyś użyć Floatzamiast tego CGFloati rzucić to zamiast
Fonix