【问题标题】:Convenience initialization of UINavigationController subclass makes subclass constant init twiceUINavigationController 子类的便捷初始化使得子类常量初始化两次
【发布时间】:2016-12-21 12:10:02
【问题描述】:

我有 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)

附:上面代码的 Playground 日志:

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

【问题讨论】:

    标签: ios swift uinavigationcontroller


    【解决方案1】:

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

    本质上,Obj-C 底层超类正在泄漏内存,并且您的 service 属性被初始化两次,因为这种 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)
        }
    }
    

    从你的实现中改变的只是在你的类本身被初始化之后才初始化service

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

    【讨论】:

    • 感谢您的回答。而且我仍然不明白为什么这两种情况下便利的初始化行为不同?
    • 所以convenience初始化使用上面的Objective-C示例初始化模式,其中有两个初始化调用([super init][self.class alloc] init...]。根据我的理解,指定的初始化程序将直接进入[self.class alloc] init...] 初始化程序路径,因此不会双重初始化,这就是导致您看到的问题的原因。
    • 我认为在这两种情况下我都调用了指定的初始化程序,不是吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-21
    • 1970-01-01
    相关资源
    最近更新 更多