我有UINavigationController和UITableViewController的子类.
为了初始化子类,我决定使用一些方便的init方法来调用超类的一些指定的初始化器.此外,每个子类都有一些常数:
let someValue: SomeClass = SomeClass()
每个类都通过调用其新创建的方便init方法来成功初始化.
问题是在UINavigationController子类中,let常量被初始化为TWICE.
import UIKit
import PlaygroundSupport
final class Navigation: UINavigationController {
convenience init(anyObject: Any) {
self.init(rootViewController: UIViewController())
}
let service = Constant("Constant Initialization -> Navigation")
}
final class Table: UITableViewController {
convenience init(anyObject: Any) {
self.init(style: .plain)
}
let service = Constant("Constant Initialization -> Table")
}
class Constant: NSObject {
init(_ string: String) {
super.init()
debugPrint(string)
}
}
Navigation(anyObject: NSNull())
Table(anyObject: NSNull())
我们是否允许使用如上所述的方便init?为什么?
为什么这两种情况下的方便init行为是不同的?
检查:版本8.2 beta(8C30a),版本8.2(8C38),版本8.2.1(8C1002)
附:上述代码的游乐场日志:
"Constant Initialization -> Navigation" "Constant Initialization -> Navigation" "Constant Initialization -> Table"
解决方法
所以这似乎是与Swift奇怪的“预期行为”.它发生的原因是由于不断的初始化属性服务.也就是说,这篇文章总结了你看到的问题:
blog post
本质上,Obj-C底层的超类是泄漏内存,并且由于Obj-C初始化的这种模式,您的服务属性被初始化了两次:
- (id)init {
self = [super init];
if (self) {
self = [[self.class alloc] initWithNibName:nil bundle:nil];
}
return self;
}
避免这种情况的简单解决方案是以下模式:
import UIKit
final class NavigationController: UINavigationController {
var service: ObjectTest?
convenience init() {
self.init(rootViewController: UIViewController())
self.service = ObjectTest("init nav")
}
}
class ObjectTest: NSObject{
init(_ string: String) {
super.init()
print(string)
}
}
所有这些都是从您的实现中改变的,只有在您的类本身初始化后才初始化服务.
另一种解决方案是使用指定的初始化器来进行超类的初始化.这意味着你不要使用一个方便的初始化器,它将使用上述的Obj-C初始化模式.