在ios 8 beta 5中,视图控制器的nib文件被破坏了吗?

我在ios 8 beta 4中创build了一个testing项目,作为主视图控制器和第二个视图控制器,创build为具有xib文件的UIViewController子类。

我在主控制器上放了一个button来显示第二个控制器:

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

}

我运行应用程序,然后按下button呈现第二个控制器 – 一切都很好

移动到Xcodetesting版5,我运行该应用程序,当我按下button的屏幕变黑。

因为我知道他们与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所接受的所有可能的组合都不起作用。

如果我使用故事板来创build另一个控制器,并继续这一切都很好。

有任何想法吗?

编辑 – 新的信息

  1. 在初始化尝试nibName =零 – 同样的问题
  2. 在目标c中创build相同的应用程序,它工作正常

显然是一个迅速的testing版5问题

我不知道这是否是一个错误,但这绝对是一个变化。 当然,他们可能会改变它…无论如何,种子5的规则是:

视图控制器不会因为它具有相同的名称自动find.xib。 您必须明确提供名称。

所以,在你的情况下,初始化这个视图控制器的任何尝试必须最终调用nibName:bundle:显式nib名称( "TestVC" ),我假设。

如果你想通过调用来初始化

 let vc = TestVC() 

正如你在呈现视图控制器中所做的那样,只需在显示的视图控制器中重写init()以调用super.init(nibName:"TestVC", bundle:nil) ,这就是你所需要的(除了我认为你也会需要在这里讨论的init(coder:)塞子)。

编辑你是绝对正确的,这是一个快速的问题。 发现得好。 在Objective-C中,使用init (或new )进行init仍然正常; 视图控制器正确地find它的同名.xib文件。

另一个编辑决定因素不是Objective-C或Swift是否调用init视图控制器本身是用Objective-C还是用Swift编写的。

最终编辑解决方法是声明你的Swift视图控制器是这样的:

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

圆括号中的名字除掉了引起问题的名字。 很可能在下一个版本中,这个问题将被修复,您可以再次使用@objc

另一个最后的编辑坏消息:我提交的这个错误报告回来了“按预期工作”。 他们指出,我所要做的就是在周围的模块之后命名.xib文件,例如,如果我的应用程序叫做NibFinder ,那么如果我命名我的.xib文件NibFinder.ViewController.xib ,它会在实例化ViewController()时自动findViewController()

这是真的,但在我看来,它只是重述错误; Swift查找过程正在预先考虑模块名称。 所以苹果公司说,我应该指责下,并预先给我的.xib文件相同的模块名称,而我说的是,苹果应该closures下去,并取消模块名称,因为它执行search。

编辑,这是真正的真正的最终这个错误是固定的iOS 9testing版4,所有这些解决方法变得不必要。

如果你需要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) } } 

然后用这种方法创build实例

 let vc = TestVC.instanceWithDefaultNib() 

这个把戏适合我。 如果您有基本视图控制器类,则可以覆盖返回类名(等于xib文件名)的nibName属性。

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

从这个基类inheritance的所有视图控制器都可以加载它们的xib。 例如MyViewController:BaseViewController可以加载MyViewController.xib

这里的代码,基于弗朗西斯科的答案。 它包含检查nib文件是否退出,所以当你加载没有关联xib的UIViewController时,应用程序不会崩溃(你可以在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) } }