我是从网上课程学习iOS开发,每次我做一个自定义视图(自定义表视图细胞,采集观察室等)的教练始终贯彻这个初始化:init编码器aDecoder究竟是什么?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
到底为什么总是我必须调用这个?它有什么作用?我可以将属性放入init吗?
我是从网上课程学习iOS开发,每次我做一个自定义视图(自定义表视图细胞,采集观察室等)的教练始终贯彻这个初始化:init编码器aDecoder究竟是什么?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
到底为什么总是我必须调用这个?它有什么作用?我可以将属性放入init吗?
实现一个初始化的要求是两件事情的结果:
的Liskov substitution principle。如果S是T的一个子类(例如,MyViewController
是ViewController
的子类),则S对象(MyViewController
的实例)必须能够替换T对象(实例为ViewController
)的位置。
如果在子类中明确定义了任何初始值设定项,则在Swift中不会继承初始值设定项。如果明确提供了一个初始化程序,则必须明确提供所有其他初始化程序(然后才可以拨打super.init(...)
)。基本原理见this question。它在Java中,但仍然适用。
到1点,一切原来ViewController
可以做什么,MyViewController
子类应该是能够做到的。一个这样的事情是能够从给定的NSCoder
初始化。到了第2点,你的MyViewController
子类不会自动继承这个能力。因此,您必须手动提供符合此要求的初始化程序。在这种情况下,你只需要将它委托给超类,让它做它通常会做的事情。
构造函数不被继承是非常有意义的:如果使用基类的(继承)初始化方法初始化派生类的实例,那么派生类新定义(“添加”)的非继承属性将会永远不会被初始化。 –
实际上,初始值设定项是在Swift中继承的,因为您没有在您的子类中提供任何自己的初始值设定项实现。如果新定义的非继承属性具有默认值,那么可以避免在子类中编写任何初始化器,并简单地继承所有超类的初始化器。见[这里](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID222) – TheBaj
@TheBaj好点,我忽略了这一点。 – Alexander
我会从相反的方向开始回答:如果要将视图的状态保存到磁盘,该怎么办?这被称为系列化。反过来是反序列化 - 从磁盘恢复对象的状态。
的NSCoding
协议定义了2种方法进行序列化和反序列化对象:
encodeWithCoder(_ aCoder: NSCoder) {
// Serialize your object here
}
init(coder aDecoder: NSCoder) {
// Deserialize your object here
}
那么,为什么需要它在你的自定义类?答案是Interface Builder。将对象拖放到故事板并对其进行配置时,Interface Builder会将该对象的状态序列化到磁盘上,然后在故事板出现在屏幕上时将其反序列化。您需要告诉Interface Builder如何执行这些操作。至少,如果您没有为您的子类添加任何新属性,则可以直接要求超类为您进行打包和解包,因此请致电super.init(coder: aDecoder)
。如果你的子类更复杂,你需要为子类添加你自己的序列化和反序列化代码。
这与Visual Studio的方法形成鲜明对比,该方法将代码写入隐藏文件以在运行时创建对象。
这个答案会帮助你http://stackoverflow.com/questions/24036393/fatal-error-use-of-unimplemented-initializer-initcoder-for-class谢谢 –
如果你实现了一个实现了'NSCoding'的对象,那么你需要实现这个初始化器,因为它需要实现'NSCoding'的类。您至少必须调用超类init方法。如果'NSCoder'包含你的类的编码属性,那么你可以使用这种方法来恢复那些 – Paulw11
尝试搜索。这个问题在这里已经被回答了很多次。 – matt