¿Los controlleres de vista con files nib están rotos en iOS 8 beta 5?

Creé un proyecto de testing en ios 8 beta 4 que como controller de vista principal y un segundo controller de vista creado como una subclass UIViewController con un file xib.

Puse un button en el controller principal para presentar el segundo controller:

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. } 

}

Corro la aplicación y presionar el button presenta el segundo controller, todo está bien

Pasando a xcode beta 5, ejecuto la aplicación y cuando presiono el button la pantalla se vuelve negra.

Como sé que se metieron con el código de inicio, intenté colocar anulaciones para ver que lo arreglarían:

 class TestVC: UIViewController { override init() { super.init() } requinetworking 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. } 

El mismo problema. Cambiar los requisitos y anulaciones en todas las combinaciones posibles aceptadas por xcode no tiene ningún efecto.

Si uso el guión gráfico para crear otro controller y seguirlo, todo está bien.

¿Algunas ideas?

EDITAR – Nueva información

  1. Intentado nibName = nil en init – el mismo problema
  2. Creado la misma aplicación en el objective c y funciona bien

Al parecer, un problema rápido de beta 5

No puedo decir si es un error o no, pero definitivamente es un cambio. Por supuesto que podrían cambiarlo de nuevo … En cualquier caso, la regla en la semilla 5 es:

El controller de vista no encontrará automáticamente su .xib solo porque tiene el mismo nombre. Debe proporcionar el nombre explícitamente.

Entonces, en su caso, cualquier bash de inicializar este controller de vista debe en última instancia llamar a nibName:bundle: con un nombre explícito de nib ( "TestVC" ), supongo.

Si desea poder inicializar llamando

 let vc = TestVC() 

como lo está haciendo en su controller de vista de presentación, simplemente anule init() en el controller de vista presentado para llamar a super.init(nibName:"TestVC", bundle:nil) y eso es todo lo que necesita (salvo que supongo que también lo hará Necesito el init(coder:) tapón discutido aquí ).

EDITAR Tiene toda la razón de que este es un problema de solo Swift. Bien descrito. En Objective-C, inicializar con init (o new ) todavía funciona bien; el controller de vista encuentra su file .xib epónimo correctamente.

OTRA EDICIÓN El factor determinante no es si Objective-C o Swift llaman init . Es si el controller de vista en sí está escrito en Objective-C o Swift.

EDIT FINAL La solución es declarar su controller de vista Swift como este:

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

El nombre entre paréntesis se deshace del nombre de destrozado que está causando el problema. Es probable que, en la próxima versión, esto se solucione y usted pueda @objc tomar @objc .

OTRA EDICIÓN FINAL Malas noticias: el informe de fallos que archivé en esto volvió "funciona como estaba previsto". Señalan que todo lo que tengo que hacer es nombrar el file .xib después del module circundante, por ejemplo, si mi aplicación se llama NibFinder , entonces si nombro mi file .xib NibFinder.ViewController.xib , se encontrará automáticamente al crear una instancia de ViewController()

Eso es cierto, pero en mi opinión simplemente reafirma el error; el procedimiento de búsqueda Swift está anteponiendo el nombre del module. Entonces, Apple dice que debería codearme y anteponer el mismo nombre de module a mi file .xib , mientras que estoy diciendo que Apple debería codearse y quitar el nombre del module mientras realiza la búsqueda.

EDITAR ES REALMENTE VERDADERAMENTE FINAL Este error se soluciona en iOS 9 beta 4 y todas estas soluciones temporales se vuelven innecesarias.

en caso de que necesites soporte de iOS8. Puede usar la extensión en 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) } } 

y luego, solo crea la instancia de esta manera

 let vc = TestVC.instanceWithDefaultNib() 

Este truco funciona para mí. Si tiene una class de controller de vista base, puede anular la propiedad nibName y devolver el nombre de la class (igual al nombre del file xib).

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

Todos los controlleres de vista que henetworkingan de esta class base podrían cargar su xib. ej. MyViewController: BaseViewController podría cargar MyViewController.xib

Aquí está el código, basado en la respuesta de Francesco. Contiene la comprobación si el file de nib sale, por lo que la aplicación no se bloqueará cuando cargues UIViewController que no tenga xib asociado (puedes reproducirlo en 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 } } 

Swift3:

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