IBOutlet є нульовим, але він з'єднаний в раскадровці, Swift


102

Використання Swift 1.1 та Xcode 6.2.

У мене є UIStoryboard, що містить сингулярний, спеціальний UIViewControllerпідклас. На ній у мене є @IBOutletз'єднання типу UIViewвід цього контролера до UIView підкласу на розкладі. У мене також є подібні торгові точки для перегляду цього виду. Дивіться рисунок А.

Але під час виконання ці властивості нульові (мал. В). Хоча я запевнив, що я підключив торгові точки в Interface Builder.

Думки :

  • Чи можливо це через те, що я використовую підклас підкласу, щось псується з ініціалізацією? Я не перекреслюю жодних ініціалізаторів
  • awakeFromNib: не викликається з якихось причин
  • Можливо, він не підключається до підпрезентацій на підпреглядах

Що я спробував:

  • Збіги @IBOutletта типи предметів розкадрування точно (замість UIView)
  • Видалення властивостей та розеток та повторно їх додано

Малюнок А

Малюнок A *

Малюнок В

Малюнок В

* Закритий код у Figure A:

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

Дякую.


Чому б не змінити! до?

clearView є нульовим, оскільки не пов’язаний із дошкою розміщення (див. коло зліва від коду з отвором, який вказує, що він не пов'язаний), на скріншоті я не бачу декларації annotationOptionView.
Шрифт Хав'єра Флореса

@JavierFloresFont: clearViewЯ очікую, що я буде нульовою . Це те, що мені ще належить рефакторифікувати. Також дивіться виноску до фігури А. @ShaanSingh Це має бути! тому що з'єднання з розкадрів (повинні бути) встановлені під час виконання та не повинні бути нульовими.
Стефан Арамбашич

Як завантажується цей контролер перегляду? Покажіть нам код, який його вимагає, або опишіть канал, який підключається до нього.
пограбувати майоф

1
Виходить правильний аркуш: let vc = UIStoryboard(name: "LocationPickerModal", bundle: nil) .instantiateViewControllerWithIdentifier("LocationPickerModalViewController") as LocationPickerModalViewController
Стефан Арамбасіч,

Відповіді:


146

Зазвичай це відбувається тому, що ваш контролер перегляду ще не завантажив свою ієрархію перегляду. Контролер перегляду завантажує свою ієрархію перегляду лише тоді, коли щось надсилає йому viewповідомлення. Система робить це тоді, коли настав час фактично поставити ієрархію перегляду на екран, що відбувається після того, як такі речі, як prepareForSegue:sender:і viewWillAppear:повернулися.

Оскільки ваш VC ще не завантажив свою ієрархію перегляду, ваші торгові точки все ще нульові.

Ви можете змусити ВК завантажувати його ієрархію подання, кажучи _ = self.view.


4
Це відбувається, коли я viewWillAppear:телефоную, коли я вперше щось роблю з цією розеткою. Доступ до перегляду для мене нічого не робить. Ще нуль.
Стефан Арамбашич

Дякую! Це працювало і для мене. var v = viewcontroller.view; змушені завантажувати ієрархію перегляду. Приємний маленький трюк! ;)
Йорді Уйтерспрот

@YordiUytersprot де ти поставив цю лінію?
Async-

4
Ну, якщо ви інстанціюєте контролер перегляду: нехай vc = self.storyboard? .InstantianteViewControllerWithIdentifier ("StoryboardIDfromVC") як? CustomVC; нехай перегляд = vc.view; // Зараз ви можете отримати доступ до IBOutlets з CustomVC тут .. vc.customTextField.text = "Lalala"; Сподіваюся, це допоможе вам! :)
Йорді Уйтерспрот

4
UIViewcontroller.loadViewIfNeeded()є правильним методом для використання тут.
orkoden

27

Ви спробували запустити Продукт> Очистити. Вирішили дуже схожу проблему для мене.


Я зробила. Вибачте, мав на увазі мою відповідь. Він почав працювати лише після того, як я видалив DerivedDataпапку для проекту.
Стефан Арамбашич

3
Лише два мої торгові точки в середині моєї ієрархії зору були нульовими. Продукт -> Clean працював на мене!
Rikco

1
Obj c, просто прибирання проекту працювало на мене ... не можу повірити, що витратив більше години і навіть не думав прибирати проект: / але дякую !!
теплиця

Просто продукт -> Clean не працював для мене, але я запустив інший симулятор, і він спрацював, тому у папці DerivedData також має бути щось не так.
endavid

22

Чи інстанціювали ви свій контролер подання із дошки розгортки або NIB, або ви створили його безпосередньо через ініціалізатор?

Якщо ви ідентифікували свій клас безпосередньо за допомогою ініціалізатора, торгові точки не будуть підключені. Інтерфейс Builder створює спеціалізовані екземпляри ваших класів і кодує ці екземпляри в NIB та дошках розкад для повторного декодування, він не визначає самих класів. Якщо це була ваша проблема, вам просто потрібно змінити код, де ви створюєте свій контролер, а натомість використовувати методи на UIStoryboard або UINib.


2
Я створюю UIStoryboardекземпляр і закликаю instantiateViewControllerWithIdentifierйого.
Стефан Арамбашич

15

Розкладочна панель не розпізнавала жодні речі, які я додав до неї. На час виконання всі посилання були нульовими. Тому я очистив отриману папку даних, а потім ці з'єднання знову працювали.


2
Це відповідь. Я боровся з цим досить довго, очищаючи папку збірки і все. У моєму випадку в viewDidLoad()усіх з'єднаннях було зроблено, але viewWillAppear()майже у всіх вони були nil(іноді один-два все-таки були з'єднані). Я все спробував і, нарешті, видалив отриману папку даних, перебудував, і все було добре.
ruttopia

6
Навіть через 3 роки Xcode 9.2 все ще має той же проклятий помилок. Дуже дякую.
Кемаль Кан Кайнак

1
Тут потрібно повідомити, що це все ще існує в Xcode 11. :(
вказівник

13

Це сталося зі мною з моєї осередку власного огляду колекції. Виявляється, мені довелося замінити метод registerClassforReuseIdentifier на registerNib. Це зафіксувало це для мене.


Ти правий. Я детально прочитав вміст підрахунку ARC у мові програмування Swift. Я не можу знайти причину, чому слабке властивість IBOutlet все ще дорівнює нулю. Нарешті, я переглядаю Google на "@IBOutlet swift nil" і знаходжу вашу відповідь в ТАК. Потім я виділив рядок Xcode шаблону додав "self.collectionView! .RegisterClass" у viewDidLoad. Потім, це працює. Ти врятуєш мені життя.
charles.cc.hsu

12

Це сталося зі мною, оскільки я випадково інстанціював свій контролер перегляду безпосередньо, а не інстанціював це через раскадровку. Якщо ви MyViewController()будете отримувати інстанцію безпосередньо через, торгові точки не будуть підключені.


Якщо ви використовуєте файл XIB, інстанція безпосередньо все ще успішно працює.
Люат Ву Дінь

11

У моєму випадку це сталося тому, що я loadViewзмінив метод у своєму підкласі ViewController, але забув додати[super loadView]

-(void)loadView {
// blank
}

Якщо ви переосмислите цей loadViewметод, на вашій підзагляді покладається ваша відповідальність. Оскільки ви її перекриєте, погляди від розробника інтерфейсів не отримують шансу перетворитись на какао-об'єкти, і тому розетки залишаються нульовими.

Якщо ви реалізуєте loadView в підкласі контролера перегляду, то ваша відповідальність завантажується елементами інтерфейсу з раскадровки / xib в код.

Або просто зателефонуйте

[super loadView];

Таким чином, щоб суперклас отримав можливість завантажити раскадровку / xib у код.


8

Ви можете зателефонувати controller.viewпримусити завантажувати представлення для ініціалізації IBOutlets, тоді ви зможете призначити значення.

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

Якщо ви подаєте копію view controllerпрограмно. Потім спробуйте створити його, як показано нижче

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

замість безпосередньо

let initialVC = InitialVC()

Це працювало для мене.


6

Для мене це сталося, коли я випадково оголосив клас свого контролера перегляду як

class XYZViewController: UINavigationController {
}

(тобто як UINavigationControllerа UIViewController).

Xcode НЕ підхоплює на цій помилці, клас , здається, побудова штрафу, і функції перевизначення , такі як viewDidLoad, viewWillAppearі т.д. все працює правильно. Але жоден ізIBOutlet не підключається.

Зміна декларації на

class XYZViewController: UIViewController {
}

виправити це повністю.


5

Я стикаюся з цією проблемою недавно! Ось моя думка. Проблема не у тому, щоб ви розгорнули розкадровку чи будь-яку проблему посилання. Йдеться про те, як ви ініціюєте ваш ViewController. Особливо, коли ви використовуєте Swift. (У створенні файлу класу в редакторі майже нічого немає)

За допомогою простого init()класу з суперкласу неможливо ініціювати все, що ви працювали з дошкою історії. Отже, що вам потрібно зробити, це змінити ініціалізацію ViewController. Замінити let XXViewController = XXViewController() на let XXViewController = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("XXViewController") as! XXViewController це вказує програмі перейти до табло, знайти XXViewController та ініціювати всеIBOutlet у вашій .

Сподіваюся, що ця допомога ~ GL


Це не було питання
Стефан Арамбасич

4

2019, ОДНА МОЖЛИВОСТІ ЦІЙ ГРОМНОЇ ПРОБЛЕМИ:

  • Скажімо, у вас, можливо, вигляд контейнера, який показує якийсь годинник. Отже, у вас є

    клас годинник: UIViewController

Ви фактично використовуєте його в ряді місць у додатку .

На головному екрані, на екрані деталей, на екрані редагування.

У вас є складний сучасний додаток, схожий на оснащення.

Насправді, Clockможе бути на самому справі завантажений більш ніж один раз в той же час де - то на одному екрані . (Можливо, в деяких випадках це приховано.)

Ви починаєте працювати над одним екземпляром Clockнад однією з багатьох своїх розповідей.

На цій дошці розповідей ви додаєте мітку, NewLabel.

Природно ви додаєте розетку в код. Все має працювати. Всі інші торгові точки прекрасно працюють.

Ви точно нав'язали розетку.

Але додаток випадає з NewLabel як нульовий.

Xcode чітко говорить про те, що ви "забули підключити розетку".

Причина в тому, що .......... у вас є "NewLabel" лише на одному із застосувань Clock!

Аварія насправді від >>> іншого місця <<<< ви використовуєте Clock !!!!

Xcode не говорить про те, що збій відбувається зовсім з іншого місця, а не з того місця, де ви працюєте!

Збій насправді не з місця, де ви працюєте - це з іншої рекламної дошки, де на цій дошці розповідей немає елемента "NewLabel" !!!

Розчарування.



2

Спершу потрібно завантажити ієрархію перегляду, щоб створити екземпляри розеток на дошці розкадрування. Для цього ви можете вручну викликати методи loadView або loadViewIfNeeded.


2

У моєму випадку додаток почало зникати раптово. Налагодження виявило, що всі торгові точки були ще nilна той час viewDidLoad().

У моїй програмі для більшості контролерів перегляду все ще використовуються гвинти (а не розкадровки). Все було на своєму місці, всі торгові точки провіднали належним чином. Я двічі перевірив.

Ми зазвичай інстанціюємо наші контролери подання як

let newVC = MYCustomViewController()

... який з певних причин, здається, працює до тих пір, як .xib названий таким же, як клас контролера перегляду (хоча не впевнений, як це працює. Хоча ми не дзвонимо init(nibName:bundle:)з аргументами нуля або переосмислюємо init()це так, selfяк це зазвичай пропонується ...).

Тому я намагався явно зателефонувати

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

... лише привітатись із помилкою виключення під час виконання:

*** Додаток, що припиняється через виняток "NSInternalInconsistencyException", причина: "Не вдалося завантажити NIB в комплекті:" NSBundle </ Користувачі / nicolasmiari / Бібліотека / Розробник / CoreSimulator / Пристрої / 3DA3CF21-108D-498F-9649-C4FC9E3C1A /Containers/Bundle/Application/C543DDC1-AE86-4D29-988C-9CCE89E23543/MyApp.app> (завантажено) "з назвою" MYCustomViewController ""

А потім я це побачив:

Не встановлено прапорець "Цільове членство" файлу .xib.


Мало статися під час вирішення одного з частих конфліктів злиття щодо файлу проекту Xcode.

Apple, безумовно, має придумати формат файлу проекту, який є більш зручним для SCM.


2

100% робоче рішення для створення ViewControllers з XIB без StoryBoards

  1. Створення класу CustomViewController: UIViewController
  2. Створіть перегляд CustomViewControllerView.xib
  3. У CustomViewControllerView.xib у програмі Interface Builder виберіть Заставники -> Власник файлу
  4. У "Інспекторі атрибутів" встановіть Class на CustomViewController
  5. У "Інспекторі з’єднань" підключіть "Вид" до подання верхнього рівня xib (переконайтесь, що Клас подання верхнього рівня не вказує на CustomViewController)
  6. У "Інспекторі з’єднань" підключіть інші торгові точки (якщо потрібно / існують)
  7. Створіть примірник CustomViewController у контролері батьківського перегляду / делегатах програми

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")

Фантастична відповідь, дякую! Щодо того, що варто, ви також можете перекрити init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)та зателефонувати на крок 7.2 selfбезпосередньо з класу CustomViewController.
brandonscript

1

Перевірте своє з'єднання IBOutlet, якщо воно підключено до власника файлу чи до перегляду. Можуть бути помилки.


1

Інший випадок:

Ваші торгові точки не будуть встановлені до тих пір, поки вигляд контролера перегляду не буде фактично підтверджений, що, напевно, відбувається незабаром після initWithNibName: bundle: - в який момент вони все ще будуть нульовими. Будь-яка установка, що стосується цих торгових точок, повинна відбуватися в методі -viewDidLoad контролера перегляду.


1

Для мене була однакова помилка на локалізованій дошці розкадрівки, елемент був доданий в одній мові, а не в іншій, тому я мав нульове посилання на цей елемент при переході на місце відсутнього локального елемента, мені довелося видалити (зайву) локалізацію для цю дошку розказок за допомогою https://stackoverflow.com/a/42256341/1356559 .


1

Для мене це було крахом тому, що containerView було нульовим.

Ось мій код із збоєм .

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

Пропала річ дзвонила super.loadView() . Тож додавання це вирішило для мене проблему.

Фіксований код :

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

ніколи не слід телефонувати loadView () безпосередньо ( developer.apple.com/documentation/uikit/uiviewcontroller/… ), а зателефонувати на self.view
Lio

1

У мене була подібна проблема, коли я раніше додав регістр (_: forCellReuseIdentifier :) для користувацької комірки після того, як я вже визначив ідентифікатор у дошці розкадрування. Був цей код у функції viewDidLoad (). Як тільки я його зняв, він справно працював.


1

Ще один випадок, з яким я просто зіткнувся. Я змінив ім’я свого класу для UIViewController, але забув змінити ім’я файлу .xib, де був побудований інтерфейс.

Одного разу я зрозумів це і змусив назви файлів відображати назву класу, все було добре!

Я сподіваюся, що хтось допомагає.


1

Отримав ще один ...

Якщо у вас є спеціальний клас для UITableViewCell, але забудьте вказати Custom у стилі комірки.


1

Ви можете перевірити, якщо вигляд "is" завантажений.

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

0
  1. виберіть обидва .hі .mперегляньте файли контролера
  2. видаліть посилання на ці файли
  3. повторно додайте файли до дерева проектів
  4. відкрийте дошку розмов, врешті реконструюйте проект

0

Випадково я підкласифікував свій контролер подання AVPlayerViewControllerзамість UIViewController. Відтворюючи його на UIViewControllerнормальні речі. Це має допомогти.

Для мене не працювало очищення збірки (нормальне та повне), видалення отриманих папок даних та вихід Xcode.


0

У мене була така ж проблема після копіювання класу (пов'язаного з xib), щоб повторно використовувати його з іншим класом перегляду контролера (зв'язане з дошкою). Я забув зняти

override var nibName

і

override var nibBundle

методи.

Після їх видалення мої торгові точки почали працювати.


0

Я бачу, ти використовуєш ViewController!? в ViewControllerкласі ви повинні використовувати -viewDidLoad, НЕ -awakeFromNib , -awakeFromNibвикористовувати для UIViewкласу



0

Якщо у вас є двоє, main.storyboardsі ви вносите зміни до неправильного, це може статися. Це може статися будь-коли, коли ви підключите розетку від ненавмисного storyboard.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.