UIViewController如何设法在Swift中使用默认的no-args初始化程序?

时间:2015-02-06 17:46:16

标签: ios swift

UIViewController类定义了一个指定的初始化器,init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)并没有方便的初始化器,但是,可以编写以下代码行并将其编译(Xcode 6.1.1)

let vc = UIViewController()

这怎么可能?

根据Swift的书,这里是初始化器继承的规则

  

规则1如果您的子类未定义任何指定的初始值设定项,则为   自动继承其所有超类指定的初始化器。

     

规则2如果您的子类提供了所有子类的实现   超类指定初始化程序 - 通过按照继承它们   规则1,或通过提供自定义实现作为其一部分   定义 - 然后它自动继承所有的超类   便利初始化者。“

     

摘自:Apple Inc.“The Swift Programming Language。”iBooks。   https://itun.es/us/jEUH0.l

因此,UIViewController无法从其祖先超级类init()继承NSObject方法,然后初始化程序来自何处?

另一方面,因为每个快速类都必须最终调用其指定的初始化程序,并不意味着initWithCoder:最终会调用init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)?然而,在实践中似乎并非如此。

2 个答案:

答案 0 :(得分:3)

Swift书中的规则适用于Swift中定义的类。 UIViewController是从ObjC导入的类,因此其行为受ObjC规则(或缺少)的约束。

在ObjC中,指定的初始化链接模式是你应该做的事情(与Swift不同,编译器强制执行它你唯一可以做的事情)。如果你调用一个继承的初始化器而不是指定的初始化器,你将获得一个实例......但是不能保证所述实例将处于合理的状态。 (事实上​​,你几乎可以肯定它不会。)ObjC课程的作者有时通过实现你不应该调用的初始化器并让它们抛出异常来练习防御性编码,但这似乎不是这里的情况。

这个特殊情况可以说是某种错误 - it wouldn't be a bad idea to file one with Apple。当从导入的ObjC API创建对象时,Swift应该强制执行初始化程序规则(在这种情况下,UIViewController需要在ObjC中使用NS_DESIGNATED_INITIALIZER)声明其指定的初始值设定项,或者UIViewController应该实现以保护反对不正确的初始化。 (尽管可能存在兼容性副作用来“修复”其中任何一种。)

答案 1 :(得分:1)

init函数上方的注释块包含以下文本:

/*
  The designated initializer. If you subclass UIViewController, you must call the super implementation of this
  method, even if you aren't using a NIB.  (As a convenience, the default init method will do this for you,
  and specify nil for both of this methods arguments.) ...
*/

据我了解,因为这是一个Objective-C类,所以允许隐式继承方法。如果您在swift中创建此类的子类,则无法访问super.init()。如果您在Objective-C代码中创建子类而没有实现自己的-[ init],那么能够使用()构建您的子类。

因为您的项目与您正在调用的类一起落入Objective-C域,所以它能够找到选择器。 Objective-C类的swift子类只遵循swift继承规则。