UIViewでinitializerを実装すると、init?(coder aDecoder: NSCoder)
も実装するように言われます。
今回はinit?(coder aDecoder: NSCoder)
と言われる理由などを調べてみます。
init?(coder aDecoder: NSCoder)
とはなにか
init?(coder aDecoder: NSCoder)
はNSCoding
プロトコルで定義されているメソッドです。
UIViewはNSCoding
に準拠しているので、このメソッドも必須になっています。
public protocol NSCoding { public func encode(with aCoder: NSCoder) public init?(coder aDecoder: NSCoder) }
NSCoding
プロトコルとは
NSCoding
プロトコルとは、そのクラスをアーカイブできるようにするものです。
NSCoding
に準拠すれば、以下のようにNSKeyedArchiver
を使ってData型への変換をする事ができます。
class MyClass: NSObject, NSCoding { override init() { super.init() } required init?(coder aDecoder: NSCoder) { } func encode(with aCoder: NSCoder) { } } let data = NSKeyedArchiver.archivedData(withRootObject: MyClass())
UIViewもNSCoding
に準拠しているのでアーカイブする事ができます。
let data = NSKeyedArchiver.archivedData(withRootObject: UIView())
NSCodingのメソッドはアーカイブ時、復元時に呼ばれます。
public protocol NSCoding { public func encode(with aCoder: NSCoder) // アーカイブする時に呼ばれる public init?(coder aDecoder: NSCoder) // アーカイブされたものを復元する時に呼ばれる }
なぜinitにrequireが付くのか
initにrequireが付く件についてテストプロトコルを作って動かしてみました。
試したところ、protocolでinitを定義するとrequireになるようです。
protocol MyProtocol { init(test: Int) } class MyClass: MyProtocol { required init(test: Int) { } }
optionalを付けるとどうなるかも試そうとしたのですが、コンパイルエラーになってしまいました。
@objc protocol MyProtocol { optional init(test: Int) // 'optional' cannot be applied to an initializerエラーになる }
公式ドキュメントにも、requiredになると書いてありました。
なぜUIViewサブクラスでinitを定義するとinit?(coder aDecoder: NSCoder)
が必要になるのか
最後に、initを定義した途端にinit?(coder aDecoder: NSCoder)
が必要になる理由についても調べてみました。
こちらはSwiftの仕様でした。
Swiftでは、initializerが1件もない時は親クラスのrequiredを再定義する必要がありません。
そのため、UIViewのサブクラスでinitを定義した途端にinit?(coder aDecoder: NSCoder)
が必要になったようです。
class MyClass { init() { } required init(test: Int) { } } class MySubclass: MyClass { }