Загрузка ViewController из файла xib

У меня были MyViewController.swift и MyViewController.xib, представляющие макет MyViewController.

Я попробовал разные методы для загрузки этого контроллера представления, включая:

//1
let myVC = UINib(nibName: "MyViewController", bundle:
       nil).instantiateWithOwner(nil, options: nil)[0] as? MyViewController

//2
let myVC = NSBundle.mainBundle().loadNibNamed("MyViewController", owner: self, options: nil)[0] as? MyViewController

//3
let myVC = MyViewController(nibName: "MyViewController", bundle: nil)

Третий - единственная успешная инициализация, но предыдущие два вызывают ошибку:

Завершение приложения из-за неперехваченного исключения "NSUnknownKeyException",

reason: '[setValue: forUndefinedKey:]: это класс не соответствует ключевому значению для ключа XXX.

Что не так с этими методами загрузки?

Ответ 1

Swift 3

let myViewController = MyViewController(nibName: "MyViewController", bundle: nil)
self.present(myViewController, animated: true, completion: nil)

или нажмите навигационный контроллер

self.navigationController!.pushViewController(MyViewController(nibName: "MyViewController", bundle: nil), animated: true)

Ответ 2

File's Owner

Обратите внимание на File Owner. В вашем случае File Owner должен быть MyViewController или его sub-class.

И следующие коды, если он выполняется в классе Foo.

// If 'self' is an instance of 'Foo' class.
// In this case, 'File Owner' will be a 'Foo' instance due to 'self' parameter.
let myVC = NSBundle.mainBundle().loadNibNamed("MyViewController", owner: self, options: nil)[0] as? MyViewController

Он назначает self как owner. Таким образом, File Owner является Foo, а не MyViewController. Тогда для класса Foo эти IBOutlet не могут быть подключены к Foo. Итак, это исключение.

Ответ 3

extension UIViewController {
    static func loadFromNib() -> Self {
        func instantiateFromNib<T: UIViewController>() -> T {
            return T.init(nibName: String(describing: T.self), bundle: nil)
        }

        return instantiateFromNib()
    }
}

Используйте это как следующее: -

let testVC = TestVC.loadFromNib()

Ответ 4

Проблема не в методах... вы, вероятно, сохранили выход (XXX), подключенный для некоторого uielement, и удалили его из соответствующего контроллера... Я добавляю пример ниже... введите описание изображения здесь

вышеуказанная кнопка подключается к контроллеру, но когда я комментирую выход введите описание изображения здесь

Мое приложение падает введите описание изображения здесь

введите описание изображения здесь

попробуйте найти выход (xxx), отсутствующий в viewcontroller, но находится в файле xib. Упование помогает:)

Ответ 5

У меня была та же проблема. Созданный автоматически xib имел UIView. Вы должны удалить представление, добавить новый контроллер представления в xib, установить класс контроллера представления в тот, который вы хотите, а затем подключить выходы. После этого вы можете использовать приведенные выше коды, чтобы получить экземпляр этого контроллера вида, например:

if let menuVC = Bundle.main.loadNibNamed("MenuViewController", owner: nil, options: nil)?.first as? MenuViewController {
            menuVC.profileType = profileType
            vc.present(menuVC, animated: true, completion: nil)
        }

Ответ 6

@AechoLiu ответ отличный. У меня был тот же вопрос, и я ответил на него с помощью приведенного ниже исправления.

Проблема:

let vc1 = NSViewController(nibName: YDNibIdentifier.myplainvc, bundle: nil)

Fix:

let vc1 = MyPlainViewController(nibName: YDNibIdentifier.myplainvc, bundle: nil)

Я случайно привел свой Nib файл к неправильному Clas (NSViewController), несмотря на то, что он правильно подключен внутри .xib файла.

Ответ 7

Попробуйте ввести код,

//1

let nib = UINib(nibName: "MyViewController", bundle:nil)
myVC = nib.instantiateWithOwner(self, options: nil)[0] as? MyViewController

ИЛИ

myVC = nib.instantiateWithOwner(self, options: nil).first as? MyViewController

//2

let nib : NSArray = NSBundle.mainBundle().loadNibNamed("MyViewController", owner: self, options: nil)
myVC = nib.objectAtIndex(0) as? MyViewController

Это будет работать.