IBOutlet jest zerowy, ale jest połączony w scenorysie, Swift


102

Korzystanie ze Swift 1.1 i Xcode 6.2.

Mam tablicę UIStoryboard zawierającą pojedynczą, niestandardową UIViewControllerpodklasę. Na nim mam @IBOutletpołączenie typu UIViewz tego kontrolera do UIView podklasy w scenorysie. Mam też podobne możliwości udostępniania podglądów tego widoku. Patrz rysunek A.

Ale w czasie wykonywania te właściwości są zerowe (Rysunek B). Chociaż zapewniłem, że podłączyłem gniazda w Interface Builder.

Myśli :

  • Czy to możliwe, że ponieważ używam podklasy podklasy, coś zepsuło inicjalizację? Nie zastępuję żadnych inicjatorów
  • awakeFromNib: nie został wezwany z jakiegoś powodu
  • Może nie łączy się z podglądami podrzędnymi

Rzeczy, których próbowałem:

  • Dokładne dopasowanie @IBOutleti typy elementów scenorysu (zamiast UIView)
  • Usunięcie nieruchomości i lokalu oraz ponowne ich dodanie

Rysunek A

Rysunek A *

Rysunek B.

Rysunek B.

* Ukryty kod w Figure Ato:

@IBOutlet private var annotationOptionsView: UIView!
@IBOutlet private var arrivingLeavingSwitch: UISegmentedControl!

Dziękuję Ci.


Dlaczego nie zmienić! do ?

clearView jest zerowe, ponieważ nie jest połączone ze scenorysem (patrz kółko po lewej stronie kodu z dziurą, która wskazuje, że nie jest połączony), na zrzucie ekranu nie widzę deklaracji annotationOptionView.
Javier Flores Font

@JavierFloresFont: clearViewSpodziewam się, że będzie zero. To jest coś, czego jeszcze nie dokonałem. Zobacz także przypis do rysunku A. @ShaanSingh Powinno! ponieważ połączenia ze scenorysów są (powinny być) ustawiane w czasie wykonywania i nie powinny być zerowe.
Stefan Arambasich

Jak ładuje się ten kontroler widoku? Pokaż nam kod, który o to prosi, lub opisz ścieżkę, która się z nim łączy.
rob mayoff

1
let vc = UIStoryboard(name: "LocationPickerModal", bundle: nil) .instantiateViewControllerWithIdentifier("LocationPickerModalViewController") as LocationPickerModalViewController
Przygotowuje

Odpowiedzi:


146

Zwykle dzieje się tak, ponieważ kontroler widoku nie załadował jeszcze swojej hierarchii widoku. Kontroler widoku ładuje swoją hierarchię widoków tylko wtedy, gdy coś wysyła do niego viewwiadomość. System robi to, gdy nadejdzie czas, aby faktycznie umieścić hierarchię widoków na ekranie, co dzieje się po takich czynnościach jak prepareForSegue:sender:iviewWillAppear: powrocie .

Ponieważ Twój VC nie załadował jeszcze swojej hierarchii widoków, Twoje punkty sprzedaży są nadal zerowe.

Możesz zmusić VC do załadowania hierarchii widoków, mówiąc _ = self.view.


4
Dzieje się tak, gdy dzwonię, kiedy viewWillAppear:po raz pierwszy robię coś z tym gniazdem. Dostęp do widoku nic mi nie daje. Wciąż zero.
Stefan Arambasich

Dzięki! U mnie też to zadziałało. var v = viewcontroller.view; zmuszony do załadowania hierarchii widoków. Niezła sztuczka! ;)
Yordi Uytersprot

@YordiUytersprot gdzie umieściłbyś tę linię?
Async

4
Cóż, jeśli utworzysz instancję viewcontroller: let vc = self.storyboard? .InstantianteViewControllerWithIdentifier ("StoryboardIDfromVC") jako? CustomVC; let view = vc.view; // W tej chwili możesz uzyskać dostęp do IBOutlets z CustomVC tutaj .. vc.customTextField.text = "Lalala"; Mam nadzieję, że ci to pomoże! :)
Yordi Uytersprot

4
UIViewcontroller.loadViewIfNeeded()jest tutaj właściwą metodą.
orkoden

27

Czy próbowałeś uruchomić produkt> Wyczyść. Rozwiązałem dla mnie bardzo podobny problem.


Zrobiłem. Przepraszam, miało to oznaczać moją odpowiedź. Zaczęło działać dopiero po usunięciu DerivedDatafolderu projektu.
Stefan Arambasich

3
Tylko dwa z moich punktów sprzedaży pośrodku mojej hierarchii widoku były zerowe. Produkt -> Czystość zadziałała!
Rikco

1
obj c, samo czyszczenie projektu zadziałało dla mnie ... nie mogę uwierzyć, że spędziłem więcej niż godzinę i nawet nie pomyślałem o wyczyszczeniu projektu: / ale dziękuję !!
szklarnia

Po prostu produkt -> Clean nie zadziałał dla mnie, ale uruchomiłem inny symulator i zadziałał, więc coś musi być nie tak w folderze DerivedData.
endavid

22

Czy utworzyłeś wystąpienie kontrolera widoku z Storyboard lub NIB, czy też utworzyłeś go bezpośrednio za pomocą inicjatora?

Jeśli utworzyłeś instancję klasy bezpośrednio z inicjatorem, gniazda nie zostaną połączone. Interface Builder tworzy niestandardowe wystąpienia twoich klas i koduje je w NIB i Storyboard w celu wielokrotnego dekodowania, nie definiuje samych klas. Jeśli to był twój problem, wystarczy zmienić kod, w którym tworzysz kontroler, aby zamiast tego użyć metod na UIStoryboard lub UINib.


2
Tworzę UIStoryboardinstancję i wzywam instantiateViewControllerWithIdentifierją.
Stefan Arambasich

16

Storyboard nie rozpoznawał żadnych dalszych elementów interfejsu użytkownika, które do niego dodałem. W czasie wykonywania wszystkie odwołania były zerowe. Więc wyczyściłem folder z danymi pochodnymi, a następnie te połączenia znów zadziałały.


2
To jest odpowiedź. Walczyłem z tym przez dłuższy czas, czyszcząc folder kompilacji i wszystko. W moim przypadku we viewDidLoad()wszystkich połączeniach były wykonane, ale w viewWillAppear()prawie wszystkich były nil(czasami jedno lub dwa były nadal połączone). Próbowałem wszystkiego i ostatecznie usunąłem folder danych pochodnych, odbudowałem i wszystko było dobrze.
ruttopia

6
Nawet po 3 latach Xcode 9.2 wciąż ma ten sam cholerny błąd. Dziękuję bardzo.
Kemal Can Kaynak

1
Tutaj, aby zgłosić, że nadal istnieje w Xcode 11. :(
Spedag

13

Przydarzyło mi się to w przypadku mojej niestandardowej komórki widoku kolekcji. Okazuje się, że musiałem zamienić metodę registerClassforReuseIdentifier na registerNib. To naprawiło to dla mnie.


Masz rację. Przeczytałem szczegółowo zawartość zliczania ARC w Swift Programming Language. Nie mogę znaleźć powodu, dla którego słaba właściwość IBOutlet nadal jest zerowa. W końcu wyszukuję w Google hasło „@IBOutlet swift nil” i znajduję odpowiedź w SO. Następnie zaznaczyłem linię szablonu Xcode, dodając „self.collectionView! .RegisterClass” w viewDidLoad. Wtedy to działa. Ratujesz mi życie.
charles.cc.hsu

12

Stało się to w moim przypadku, ponieważ przypadkowo utworzyłem instancję mojego kontrolera widoku bezpośrednio, zamiast tworzyć instancję za pośrednictwem scenorysu. Jeśli utworzysz instancję bezpośrednio przez, MyViewController()gniazda nie zostaną połączone.


Jeśli używasz pliku XIB, bezpośrednie utworzenie instancji nadal działa pomyślnie.
Luat Vu Dinh

11

W moim przypadku stało się tak, ponieważ loadViewnadpisałem metodę w mojej podklasie ViewController, ale zapomniałem dodać[super loadView]

-(void)loadView {
// blank
}

Kiedy zastępujesz loadViewmetodę, Twoim obowiązkiem jest zainicjowanie podglądów podrzędnych. Ponieważ to nadpisujesz, widoki z kreatora interfejsów nie mają szansy na konwersję na obiekty kakaowe, a zatem gniazda pozostają zerowe.

Jeśli zaimplementujesz loadView w podklasie kontrolera widoku, to Twoim obowiązkiem jest załadowanie elementów interfejsu użytkownika z storyboard / xib do kodu.

Albo po prostu zadzwoń

[super loadView];

Aby superklasa miała szansę załadować storyboard / xib do kodu.


8

Możesz wywołać controller.viewwymuszenie załadowania widoku w celu zainicjowania IBOutlets, a następnie będziesz mógł przypisać wartości.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if (segue.identifier == "identifier") {
        let controller = segue.destinationViewController as! YourController
        let _ = controller.view //force to load the view to initialize the IBOutlets

        controller.your_IBOutlet_property = xxx
        ...
        controller.delegate = self
    }
}

7

Jeśli utworzysz wystąpienie view controllerprogramu. Następnie spróbuj utworzyć go jak poniżej

let initialVC = self.storyboard?.instantiateViewController(withIdentifier: "InitialVC") as! InitialVC

zamiast bezpośrednio

let initialVC = InitialVC()

To zadziałało dla mnie.


6

W moim przypadku miało to miejsce, gdy przypadkowo zadeklarowałem klasę mojego kontrolera widoku jako

class XYZViewController: UINavigationController {
}

(tj. jako UINavigationControllernie a UIViewController).

Xcode nie odebrać na tej pomyłki, klasa wydaje budować grzywny oraz funkcji sterowania, takie jak viewDidLoad, viewWillAppearitp wszystko działa poprawnie. Ale żaden zIBOutlet jest połączone.

Zmiana deklaracji na

class XYZViewController: UIViewController {
}

naprawiłem to całkowicie.


5

Ostatnio napotykam ten problem! Oto moja myśl. Problem nie dotyczy Twojej storyboardu ani żadnego problemu z łączem. Chodzi o to, jak inicjować ViewController. Zwłaszcza jeśli używasz Swift. (Kiedy tworzysz plik klasy, w edytorze nie ma prawie nic)

Po prostu używając init()from super class nie możesz zainicjować niczego, z czym pracowałeś z storyboardem. Więc to, co musisz zrobić, to zmienić inicjalizację ViewController. Zamień let XXViewController = XXViewController() przez let XXViewController = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("XXViewController") as! XXViewController To mówi programowi, aby przejść do storyboardu, znaleźć XXViewController i zainicjować wszystkoIBOutlet w swojej serii ujęć.

Mam nadzieję, że ta pomoc ~ GL


To nie był problem
Stefan Arambasich

4

2019, JEDNA MOŻLIWOŚĆ NA TEN STRASZNY PROBLEM:

  • Załóżmy, że być może masz widok kontenera, który pokazuje jakiś rodzaj zegara. Więc masz

    klasa Zegar: UIViewController

W rzeczywistości używasz go w wielu miejscach w aplikacji .

Na ekranie głównym, na ekranie szczegółów, na ekranie edycji.

Masz skomplikowaną, nowoczesną aplikację podobną do snapchata.

W rzeczywistości Clockmoże być ładowany więcej niż raz w tym samym czasie gdzieś na tym samym ekranie . (Może w niektórych przypadkach jest ukryty).

Zaczynasz pracować nad jednym wystąpieniem Clockjednego z wielu scenariuszy.

W tej serii ujęć dodajesz etykietę NewLabel.

Oczywiście gniazdko dodajesz w kodzie. Wszystko powinno działać. Wszystkie inne gniazdka działają doskonale.

Ty na pewno związane wylot.

Jednak aplikacja ulega awarii z wartością NewLabel jako zero.

Xcode wyraźnie mówi, że „zapomniałeś podłączyć gniazdka”.

Powód jest taki .......... masz "NewLabel" tylko na jednym z zastosowań Zegara w scenorysie!

Awaria faktycznie pochodzi >>> z innego miejsca <<<< używasz Zegara !!!!

Xcode nie informuje, że awaria pochodzi z innego miejsca, a nie z miejsca, w którym pracujesz!

Awaria w rzeczywistości nie pochodzi z miejsca, w którym pracujesz - pochodzi z innego storyboardu, w którym nie ma elementu „NewLabel” w tym storyboardzie !!!

Denerwujący.



2

Najpierw musisz załadować hierarchię widoków, aby utworzyć wystąpienie gniazd w serii ujęć. W tym celu możesz ręcznie wywołać metody loadView lub loadViewIfNeeded.


2

W moim przypadku aplikacja nagle zaczęła się zawieszać. Debugowanie go ujawniło, że wszystkie punkty sprzedaży nadal działały nilw czasie viewDidLoad().

Moja aplikacja nadal używa końcówek (nie scenorysów) dla większości kontrolerów widoku. Wszystko było na swoim miejscu, wszystkie gniazdka prawidłowo okablowane. Sprawdziłem dwukrotnie.

Zwykle tworzymy wystąpienia naszych kontrolerów widoku jako

let newVC = MYCustomViewController()

... które z jakiegoś powodu wydaje się działać tak długo, jak .xib nazywa się tak samo jak klasa widoku kontrolera (nie wiem, jak to działa, choć. Jesteśmy nie dzwoni init(nibName:bundle:)z zerowymi argumentów, lub nadrzędnymi init()to zrobić na selflike it jest zwykle sugerowane ...).

Więc spróbowałem wyraźnie zadzwonić

 let newVC = MYCustomViewController(nibName: "MYCustomViewController", bundle: .main)

... tylko do powitania z błędem wyjątku w czasie wykonywania:

*** Zamykanie aplikacji z powodu nieprzechwyconego wyjątku „NSInternalInconsistencyException”, przyczyna: „Nie można załadować NIB w pakiecie:„ NSBundle </ Users / nicolasmiari / Library / Developer / CoreSimulator / Devices / 3DA3CF21-108D-498F-9649-C4FC9E3C1A8D / data /Containers/Bundle/Application/C543DDC1-AE86-4D29-988C-9CCE89E23543/MyApp.app> (załadowano) 'o nazwie' MYCustomViewController '

I wtedy to zobaczyłem:

Pole wyboru „Członkostwo docelowe” w pliku .xib nie zostało zaznaczone.


Musiało się to wydarzyć podczas rozwiązywania jednego z częstych konfliktów scalania dotyczących pliku projektu Xcode.

Apple zdecydowanie musi wymyślić format pliku projektu, który byłby bardziej przyjazny dla SCM.


2

W 100% działające rozwiązanie do tworzenia ViewControllerów z XIB bez StoryBoards

  1. Utwórz klasę CustomViewController: UIViewController
  2. Utwórz widok CustomViewControllerView.xib
  3. W CustomViewControllerView.xib w Interface Builder wybierz Placeholder -> File's Owner
  4. W „Inspektorze atrybutów” ustaw Class na CustomViewController
  5. W „Inspektorze połączeń” połącz „widok” z widokiem najwyższego poziomu xib (upewnij się, że klasa widoku najwyższego poziomu nie wskazuje na CustomViewController)
  6. W „Inspektorze połączeń” podłącz inne gniazda (jeśli są potrzebne / istnieją)
  7. Utwórz wystąpienie CustomViewController w nadrzędnym kontrolerze widoku / delegacie aplikacji

7.1.

// creating instance
let controller = CustomViewController()

7.2.

// connecting view/xib with controller instance
let bundle = Bundle(for: type(of: controller))
bundle.loadNibNamed("CustomViewControllerView", owner: controller, options: nil)

7.3.

// get/set outlets
controller.labelOutlet.text = "title"
controller.imageOutlet.image = UIImage(named: "image1")

Fantastyczna odpowiedź, dzięki! Ze względu na swoją wartość można również zastąpić init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)i wywołać krok 7.2 selfbezpośrednio w klasie CustomViewController.
brandonscript

1

Sprawdź połączenie IBOutlet, jeśli jest połączone z właścicielem pliku lub widokiem. Mogą być błędy.


1

Inny przypadek:

Twoje wyloty nie zostaną ustawione, dopóki widok kontrolera widoku nie zostanie faktycznie utworzony, co w twoim przypadku prawdopodobnie dzieje się wkrótce po initWithNibName: bundle: - w którym to momencie nadal będą zerowe. Każda konfiguracja, którą wykonujesz, która obejmuje te gniazda, powinna być wykonywana w metodzie -viewDidLoad kontrolera widoku.


1

U mnie miałem ten sam błąd na zlokalizowanej planszy scenorysu, element został dodany w jednym locale, a nie w innym, więc miałem zerowe odniesienie do tego elementu po przełączeniu na brakujące ustawienie regionalne, musiałem usunąć (nadmiarową) lokalizację dla ten scenorys przy użyciu https://stackoverflow.com/a/42256341/1356559 .


1

Dla mnie to się zawiesiło, ponieważ containerViewbyło zero.

Oto mój kod z Crash .

@IBOutlet private var containerView: UIView!  // Connected to Storyboard
override open func loadView() {
    containerView.addSubview(anotherView)
}

Brakująca rzecz nazywała się super.loadView(). Więc dodanie tego rozwiązało problem.

Naprawiono kod :

@IBOutlet private var containerView: UIView!
override open func loadView() {
    super.loadView()
    containerView.addSubview(anotherView)
}

nie powinieneś nigdy bezpośrednio wywoływać loadView () ( developer.apple.com/documentation/uikit/uiviewcontroller/… ), zamiast tego wywołaj self.view
Lio

1

Miałem podobny problem, gdy wcześniej dodałem register (_: forCellReuseIdentifier :) dla niestandardowej komórki po tym, jak już zdefiniowałem identyfikator w scenorysie. Miał ten kod w funkcji viewDidLoad (). Po usunięciu działało dobrze.


1

Kolejny przypadek, z którym właśnie się spotkałem. Zmieniłem nazwę mojej klasy dla UIViewController, ale zapomniałem zmienić nazwę pliku .xib, w którym został zbudowany interfejs.

Kiedy to złapałem i sprawiłem, że nazwy plików odzwierciedlały nazwę klasy, wszystko było dobrze!

Mam nadzieję, że to komuś pomoże.


1

Mam jeszcze jednego ...

Jeśli masz klasę niestandardową dla UITableViewCell, ale zapomnisz określić Custom w Style komórki.


1

Możesz sprawdzić, czy widok jest załadowany.

if isViewLoaded && view.window != nil {
 //self.annotationOptionsView.
}

0
  1. wybierz oba .hi .mwyświetl pliki kontrolera
  2. usuń odniesienia do tych plików
  3. ponownie dodaj pliki do drzewa projektu
  4. otwórz scenorys i ostatecznie odbuduj projekt

0

Przypadkowo podklasowałem mój kontroler widoku z AVPlayerViewControllerzamiast UIViewController. Odtworzenie tego do UIViewControllernormalnego stanu. To powinno pomóc.

Żadne czyszczenie kompilacji (normalne i pełne), usuwanie folderów danych pochodnych i zamykanie Xcode działało dla mnie.


0

Miałem ten sam problem po skopiowaniu klasy (połączonej z xib), aby ponownie użyć jej z inną klasą viewcontroller (połączoną ze scenorysem). Zapomniałem usunąć

override var nibName

i

override var nibBundle

metody.

Po ich usunięciu moje gniazdka zaczęły działać.


0

Widzę, że używasz ViewController!? w ViewControllerklasie Państwo musi użyć -viewDidLoad, nie -awakeFromNib , -awakeFromNibużyj dla UIViewklasy



0

Jeśli masz dwa main.storyboardsi wprowadzasz zmiany w niewłaściwym, może się to zdarzyć. Może się to zdarzyć za każdym razem, gdy podłączysz gniazdko z niezainicjowanego storyboard.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.