Являются ли контроллеры просмотра с файлами 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)
}
}