UINavigationController子类的便捷初始化使子类常量初始化两次

时间:2016-12-21 12:10:03

标签: ios swift uinavigationcontroller

我有UINavigationControllerUITableViewController的子类。

为了初始化子类,我决定使用一些调用超类的指定初始值设定项的convenience init方法。此外,每个子类都有一些let常量:

let someValue: SomeClass = SomeClass()

通过调用新创建的convenience init方法成功初始化每个类。

问题是let常量在UINavigationController子类中初始化 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())

我们是否可以像上面一样使用convenience init?为什么呢?

为什么convenience init行为在这两种情况下有所不同?

选中:版本8.2 beta(8C30a)版本8.2(8C38)版本8.2.1(8C1002)

P.S。以上代码的游乐场日志:

"Constant Initialization -> Navigation"
"Constant Initialization -> Navigation"
"Constant Initialization -> Table"

1 个答案:

答案 0 :(得分:4)

所以这似乎与Swift一样奇怪的“预期行为”。它发生的原因是由于常量初始化属性service。也就是说,这篇文章总结了您看得很清楚的问题:blog post

基本上,Obj-C底层超类正在泄漏内存,并且由于Obj-C初始化模式,您的service属性被初始化两次:

- (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)
    }
}

只有在您的类本身初始化后才会初始化service

另一种解决方案是使用指定的初始化程序为超类初始化。这意味着您不使用将使用上述Obj-C初始化模式的便利初始化程序。