Mast call a designated initializer of the superclass
‘required’ initializer ‘init(coder:)’ must be provided by subclass of
如果你要用 Swift
创建一个实现了 NSCoding
协议的类(UIView,UIViewController
)的子类的时候,你就会发现一种很尴尬的情况,required init?(coder aDecoder: NSCoder)
, 还是必须实现的,然而你可能并不知道这是什么鬼,也不知道有什么卵用,你可能只是简单的知道他是 NSCoding
的协议方法而已.
在
Swift
中,如果你要重写父类的构造器,并且父类实现了NSCoding
,那么在子类中你也必须实现这个构造器required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
所以你觉得万事大吉了,对不起,你错了。
Swift
在类初始化时,出于对安全性的考虑,对类的所有内部属性必须全部被初始化(通俗一点就是分配一个默认值),否则编译器报错,next eg.class ViewController: UIViewController { var name: String var age : Int init() { name = "Paul" age = 24 super.init(nibName: nil, bundle:nil) } required init(coder: NSCoder) { super.init(coder: coder) } }
- 有些人说话了,谁说了一定要初始化,比如
var age : Int?
就不需要在super.init()
之前必须初始化,?
是可选型符号,这种写法规定你的age
属性是个可选型,什么是可选型,可选型是指,在你没有赋值的情况下默认赋值为nil
,所以即使age
定义的时候没有初始化,但是它已经被初始化了(nil 表示空值,和OC中的空对象区别,例如 Swift 中是不能通过 age=nil 来释放一个对象的), 但是,如果你想要实现一个自定义的构造器,怎么做,我猜可能是这样
class ViewController: UIViewController { let name: String init() { name = "Paul" super.init(nibName: nil, bundle:nil) } init(name aName : String) { name = "Paul" super.init(nibName: nil, bundle:nil) } required init(coder: NSCoder) { name = "Paul" \\ 索性都写上, super.init(coder: coder) } }
如果我有10个,100个属性呢?耗时间,那干脆想oc一样,写一个赋值的方法
class ViewController: UIViewController { let name: String init() { setup() super.init(nibName: nil, bundle:nil) } init(name aName : String) { setup() super.init(nibName: nil, bundle:nil) } required init(coder: NSCoder) { setup() super.init(coder: coder) } func setup() { name = "Paul" age = 25 } }
这样一来有一百个也无妨,想法很不错,有见地,但是很可惜,编译未通过,(举个例子,对象好比蛋里面的鸡,属性是肌肉,方法是鸡翅、鸡爪等),在
super.init
之前(蛋孵化之前),方法也同样没有被初始化(鸡都没有孵出来,你就想烤鸡翅了?)废话说了这么多,到底怎么解决呢,别着急,
class ViewController: UIViewController { let name: String // 自定义的构造器 init(_ coder: NSCoder? = nil) { name = "Paul" if let coder = coder { super.init(coder: coder)! } else { super.init(nibName: nil, bundle:nil) } } required convenience init(coder: NSCoder) { self.init(coder) } // 下面这句可省去 override convenience init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { self.init(nil) } }
像这样,我们在我们自定义的构造器
init(_ coder: NSCoder? = nil)
中添加了一个可选型的NSCoding
的参数,默认是nil,所以我们像之前那样不用任何参数调用init(nil)