Являются ли контроллеры просмотра с файлами nib, разбитыми на ios 8 beta 5?

Я создал тестовый проект в ios 8 beta 4, который как главный контроллер представления и второй контроллер представлений, созданный как подкласс UIViewController с xib файлом.

Я поставил кнопку на главном контроллере, чтобы представить второй контроллер:

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

@IBAction func testVCBtnTapped() {
    let vc = TestVC()
    presentViewController(vc, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

}

Я запускаю приложение и нажимаю кнопку, представляет второй контроллер - все хорошо

Переходя к xcode beta 5, я запускаю приложение, и когда я нажимаю кнопку, экран становится черным.

Так как я знаю, что они испортили код init, я попытался включить в него переопределения, чтобы это исправить:

class TestVC: UIViewController {

override init() {
    super.init()
}
required init(coder aDecoder: NSCoder!) {
    super.init(coder: aDecoder)
}
override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

Такая же проблема. Изменение требуемого и переопределения во все возможные комбинации, принятые xcode, не имеет эффекта.

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

Любые идеи?

EDIT - новая информация

  • Пробовал nibName = nil в init - та же проблема
  • Создал одно и то же приложение в объективе c и отлично работает

По-видимому, быстрая проблема с бета-тестированием

Ответ 1

Я не могу сказать, является ли это ошибкой или нет, но это определенно изменение. Конечно, они могут изменить его обратно... В любом случае, правило в семени 5:

Контроллер представления не автоматически найдет свой .xib только потому, что он имеет то же имя. Вы должны указать имя явно.

Итак, в вашем случае любая попытка инициализировать этот контроллер представления должна в конечном итоге вызвать nibName:bundle: с явным именем nib ("TestVC"), я предполагаю.

Если вы хотите, чтобы иметь возможность инициализировать, вызывая

let vc = TestVC()

как вы это делаете в своем представлении, а затем просто переопределите init() в представленном контроллере представления для вызова super.init(nibName:"TestVC", bundle:nil) и что все, что вам нужно (кроме того, я полагаю, вам также понадобится init(coder:) stopp Обсуждаемый здесь).

EDIT. Вы абсолютно правы, что это проблема только для Swift. Хорошо подмечено. В Objective-C инициализация с помощью init (или new) все еще работает нормально; контроллер просмотра правильно находит свой одноименный .xib файл.

ДРУГОЕ ИЗОБРАЖЕНИЕ Определяющим фактором является не Objective-C, либо Swift вызывает init. Именно сам диспетчер представлений записывается в Objective-C или Swift.

ЗАКЛЮЧИТЕЛЬНОЕ ИЗОБРАЖЕНИЕ. Обходным путем является объявление вашего контроллера вида Swift следующим образом:

@objc(ViewController) ViewController : UIViewController { // ...

Имя в круглых скобках избавляется от искажения имени, которое вызывает проблему. Вероятно, что в следующем выпуске это будет исправлено, и вы можете снова взять @objc.

ДРУГОЕ ОКОНЧАТЕЛЬНОЕ ИЗОБРАЖЕНИЕ Плохая новость: отчет об ошибке, который я подал на это, вернулся "работает по назначению". Они указывают, что все, что мне нужно сделать, это назвать .xib файл после окружающего модуля, например. если мое приложение называется NibFinder, то, если я назову свой файл .xib NibFinder.ViewController.xib, он будет найден автоматически при создании экземпляра ViewController().

Это правда, но, на мой взгляд, он просто повторяет ошибку; процедура Swift lookup добавляет имя модуля. Так что Apple заявляет, что я должен судорожно поддаваться и добавлять одно и то же имя модуля в мой .xib файл, тогда как я говорю, что Apple должна сужаться и стирать имя модуля, когда он выполняет поиск.

ИЗМЕНИТЬ, ЧТО ИСКЛЮЧИТЕЛЬНО ИСКЛЮЧИТЕЛЬНО ОКОНЧАТЕЛЬНО Эта ошибка исправлена ​​в iOS 9 beta 4, и все эти обходные пути становятся ненужными.

Ответ 2

если вам нужна поддержка iOS8. Вы можете использовать расширение на UIViewController

extension UIViewController {
    static func instanceWithDefaultNib() -> Self {
        let className = NSStringFromClass(self as! AnyClass).componentsSeparatedByString(".").last
        let bundle = NSBundle(forClass: self as! AnyClass)
        return self.init(nibName: className, bundle: bundle)
    }
}

а затем просто создайте экземпляр таким образом

let vc = TestVC.instanceWithDefaultNib()

Ответ 3

Этот трюк работает для меня. Если у вас есть класс контроллера базового представления, вы можете переопределить свойство nibName, возвращающее имя класса (равное имени файла xib).

class BaseViewController: UIViewController {

   override var nibName: String? {
      get {
         guard #available(iOS 9, *) else {
            let nib = String(self.classForCoder)
            return nib
         }

         return super.nibName
       }
    }
}

Все контроллеры представлений, которые наследуют от этого базового класса, могут загрузить свой xib. например MyViewController: BaseViewController может загрузить MyViewController.xib

Ответ 4

Здесь код, основанный на ответе Франческо. Он содержит проверку, если файл nib завершен, поэтому приложение не будет разбиваться при загрузке UIViewController, у которого нет связанного xib (вы можете воспроизвести его на iOS8)

override var nibName: String? {
    get {
        let classString = String(describing: type(of: self))
        guard nibBundle?.path(forResource: classString, ofType: "nib") != nil else {
            return nil
        }
        return classString
    }
}
override var nibBundle: Bundle? {
    get {
        return Bundle.main
    }
}

Ответ 5

Swift3:

extension UIViewController {
    static func instanceWithDefaultNib() -> Self {
        let className = NSStringFromClass(self).components(separatedBy: ".").last
        return self.init(nibName: className, bundle: nil)
    }
}