UIView或UIViewController何时调用"required init?(coder aDecoder: NSCoder)"?

22

当我创建UIViewUIViewController的子类并带有存储属性时,如果我不包含 required init?(coder aDecoder: NSCoder) 的实现,Xcode 将无法编译我的项目。目前,我有以下实现来消除编译器的警告:

required init?(coder aDecoder: NSCoder) {
    fatalError()
}

我理解为什么需要包含这个初始化器;我的子类需要遵循NSCoding协议,因为它的超类遵循该协议,而这个初始化器是NSCoding协议的一部分,因此它需要与我的类一起工作,即初始化我类的所有存储属性(超类版本的初始化器不会这样做)。

我想一个正确的实现看起来应该像这样:

class MyView: UIView {
    let label: UILabel

    override init(frame: CGRect) {
        label = UILabel()
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        if let label = aDecoder.decodeObject() as? UILabel {
            self.label = label
        } else {
            return nil
        }
        super.init(coder: aDecoder)
    }

    override func encode(with aCoder: NSCoder) {
        aCoder.encode(label)
        super.encode(with: aCoder)
    }
}

然而,考虑到我的应用程序有50多个自定义视图和视图控制器,正确地在每个自定义视图和视图控制器中实现这个功能是一项很大的工作。

因此,我想知道是否需要正确地实现这个初始化程序,或者是否可以只让它抛出致命错误。换句话说,如果我在自己的代码中不调用它,这个初始化程序会被调用吗?我想我读到过它可能被Storyboard调用,但我的应用程序没有使用任何Storyboard。


5
如果您的视图实例被用于故事板场景或XIB文件中,这个初始化方法将会被调用。 - Paulw11
2
@Paulw11,你应该把它发布为答案。 - Duncan C
2个回答

21

如果您的视图实例在Storyboard场景中使用,将调用此初始化程序。

是否创建一个功能性的初始化程序由您决定,但大多数情况下,这只是从init(frame:)代码复制的问题。


好的。作为对此的后续,如果我选择不制作一个功能性的初始化器,有没有更好的方法来标记它,而不是只是抛出致命错误?也就是说,有没有一种方法可以将其标记为编译器错误,如果有人试图从代码中调用它,而不是运行时错误? - kmell96
1
不可以,你可以调用致命错误(fatal error),或者返回 nil,因为这是一个可失败的初始化方法。 - Paulw11
NSCoder不是只用于storyboard吗?我从未见过它与xib一起使用。 - F3R1
一个Storyboard基本上只是一堆带有一些额外信息的Xib文件;当在应用程序中使用时,没有太大的区别。 - Tino
回答我上面的跟进问题,现在有一种方法可以标记此初始化程序,以便它会导致编译器错误。只需使用不可用声明:@available(*, unavailable) required init?(coder: NSCoder) - kmell96

2

它提供了一个NSCoder实例作为参数,只有在使用iOS序列化API时才需要。这并不经常使用,所以您可以忽略它。如果您想了解,序列化将对象转换为字节流,您可以将其保存在磁盘上或通过网络发送。

在视图控制器的初始化期间,通常会分配视图控制器在其生命周期中需要的资源。因此,这包括模型对象或其他辅助控制器,如网络控制器。

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接