[英]Why does the Swift default initializer of a UIViewController subclass initialize the properties twice?
Why does the Swift default initializer init()
of a UIViewController subclass initialize the properties twice? 为什么UIViewController子类的Swift默认初始化程序init()
初始化属性两次? The same thing happens with subclasses of UIView, but not with a direct subclass of NSObject. UIView的子类也会发生同样的事情,但NSObject的子类却没有。
The problem goes away by using Parent(nibName: nil, bundle: nil)
instead of Parent()
for initialization. 通过使用Parent(nibName: nil, bundle: nil)
而不是Parent()
进行初始化,问题就消失了。 It also works correctly when I provide custom initializers for Parent
. 当我为Parent
提供自定义初始化程序时,它也可以正常工作。
I know how to work around this problem, but I am curious about why it happens. 我知道如何解决这个问题,但我很好奇它为什么会发生。
The problem can be reproduced by copying this code into an Xcode 6.0.1 Playground. 通过将此代码复制到Xcode 6.0.1 Playground中可以重现该问题。
import UIKit
class Child {
init() {
println("Child init")
}
}
class Parent: UIViewController {
let child = Child()
}
// This way "Child init" is printed twice:
let parent = Parent()
// This way "Child init" is printed once:
//let parent = Parent(nibName: nil, bundle: nil)
Update: When I define a fake class that has similar initializers like the ones UIViewController
has and use that as the superclass of Parent
both ways to initialize it work and print "Child init" only once. 更新:当我定义一个假类,它具有类似UIViewController
所具有的类似初始化器并将其用作Parent
的超类时,两种初始化方法都工作并且只打印一次“Child init”。
import UIKit
class Child {
init() {
println("Child init")
}
}
class FakeViewController : UIResponder {
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
}
convenience override init() {
self.init(nibName: nil, bundle: nil)
}
}
class Parent: FakeViewController {
let child = Child()
}
// With the FakeViewController both initializers cause "Child init" to be printed once:
let parent = Parent()
//let parent = Parent(nibName: nil, bundle: nil)
let parent = Parent()
in the first example should not even compile? 也许它不是, let parent = Parent()
第一个例子中的let parent = Parent()
甚至不应该编译? The first print occurs when constructing the Parent instance; 构造Parent实例时发生第一次打印; all of the instance fields are initialized at that point, which includes creating the Child instance. 此时初始化所有实例字段,包括创建Child实例。
The second print occurs when the implicit super.init
is called of the Parent. 当调用Parent的隐式super.init
时,会发生第二次打印。 Given that the code for this is closed, it's impossible to know for sure what is happening; 鉴于此代码已关闭,无法确切知道发生了什么; but the problem probably stems from the fact that the init
is a convenience initializer in UIViewcontroller
(the designated initializer is init:nibName:bundle
). 但问题可能源于这样一个事实,即init
是UIViewcontroller
一个便利初始化UIViewcontroller
(指定的初始化器是init:nibName:bundle
)。 Documentation in the UIVIewController states that when it is overridden, the required initializer must be called. UIVIewController中的文档声明,当它被覆盖时,必须调用所需的初始化程序。
So to correct this, you need to add: 所以要纠正这个问题,你需要添加:
class Parent: UIViewController {
override init() {
super.init(nibName:nil,bundle:nil)
}
// the following is also required if implementing an initializer
required init(coder:NSCoder) {
super.init(coder:coder)
}
}
See https://developer.apple.com/library/prerelease/iOS/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_319 for more information about designated vs convenience initializers. 有关指定与便利初始化程序的详细信息,请参阅https://developer.apple.com/library/prerelease/iOS/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_319 。
Apparently, UIViewContoller
's init
is implemented like: 显然, UIViewContoller
的init
实现如下:
- (instancetype)init {
self = [super init]; // <- not sure
if(self) {
self = [[self.class alloc] initWithNibName:nil bundle:nil];
}
return self;
}
You can see, with debugger, that self
of Parent
has different address between first Child()
call and second one. 您可以使用调试器看到Parent
self
在第一个Child()
调用和第二个调用之间具有不同的地址。
In Swift, properties are initialised before the owner object is initialised. 在Swift中,在初始化所有者对象之前初始化属性。 that is why your Child()
is get called twice. 这就是你的Child()
被调用两次的原因。
This problem has been fixed in Xcode 6.3. Xcode 6.3中已修复此问题。 The last version where I can reproduce the bug is Xcode 6.2. 我可以重现该错误的最后一个版本是Xcode 6.2。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.