はじめに
この記事では、required 修飾子について説明します。
他の記事へのリンク
- [Swift] クラスのイニシャライザ1: イニシャライザの引数の書き方
- [Swift] クラスのイニシャライザ2: プロパティの初期化方法
- [Swift] クラスのイニシャライザ3: Designated Initializer と Convenience Initializer
- [Swift] クラスのイニシャライザ4: override 修飾子
- [Swift] クラスのイニシャライザ5: required 修飾子
- [Swift] クラスのイニシャライザ6: Failable Initializer
環境
- Xcode 6.1 (Playground)
required 修飾子とは?
required 修飾子は、以下の2つの状況で使います。
- 状況1) サブクラスにイニシャライザのオーバーライドを強制するとき
- 状況2) プロトコルのイニシャライザをオーバーライドするとき
状況1) サブクラスにイニシャライザのオーバーライドを強制するとき
Designated -> Designated の場合
class Animal {
let name: String
//
// A(サブクラスにイニシャライザのオーバーライドを強制するときは、required 修飾子を付ける)
//
required init() {
self.name = "unknown"
}
}
class Cat: Animal {
//
// A をオーバーライド(override 修飾子ではなく、required 修飾子を使うことに注意)
//
required init() {
super.init()
}
}
サブクラスにイニシャライザのオーバーライドを強制するときは、required 修飾子を使います。
//
// A(サブクラスにこのイニシャライザのオーバーライドを強制するときは、required 修飾子を付ける)
//
required init() {
self.name = "unknown"
}
また、required 修飾子の付いたスーパクラスのイニシャライザをオーバーライドするときにも、required 修飾子を使います。
この場合には、override 修飾子ではなく、required 修飾子を使うことに注意してください。
//
// A をオーバーライド(override 修飾子ではなく、required 修飾子を使うことに注意)
//
required init() {
super.init()
}
補足1) override 修飾子ではなく、required 修飾子を使う理由
上記で override 修飾子を使えないのは、サブクラスのサブクラスにイニシャライザのオーバーライドを強制するためではないかと思われます。
class Animal {
let name: String
//
// A
//
required init() {
self.name = "unknown"
}
}
class Cat: Animal {
//
// A'(A をオーバーライド。ここに required 修飾子がないと、サブクラス PersianCat に、このイニシャライザのオーバーライドを強制できない)
//
required init() {
super.init()
}
}
class PersianCat: Cat {
//
// A' をオーバーライド
//
required init() {
super.init()
}
}
補足2) インスタンスメソッドでは、required 修飾子を使用できない
required 修飾子はイニシャライザでしか使えません。インスタンスメソッドでは使用できません。
class Animal {
required func makeSound() { // -> error: 'required' may only be used on 'init' declarations
}
}
Designated -> Convenience の場合
class Animal {
let name: String
//
// A
//
init(name: String) {
self.name = name
}
//
// B
//
required convenience init() {
self.init(name: "unknown")
}
}
class Cat: Animal {
//
// B をオーバーライド
//
required init() {
//
// A を呼び出す
//
super.init(name: "unknown")
}
}
Convenience -> Designated の場合
class Animal {
let name: String
//
// A
//
init() {
self.name = "unknown"
}
//
// B
//
required init(name: String) {
self.name = name
}
}
class Cat: Animal {
//
// B をオーバーライド
//
required convenience init(name: String) {
//
// スーパークラスから自動的に継承された A を呼び出す(下記の「注意1」「注意2」を参照)
//
self.init()
}
}
注意1)
self.init()
では、スーパークラスから自動的に継承されたイニシャライザを呼び出しています。
詳細は、以下の記事を参照してください。
- [Swift] クラスのイニシャライザ3: Designated Initializer と Convenience Initializer の「9. イニシャライザの自動的な継承」
注意2)
オーバーライドをしている場合でも、convenience initializer の中では、スーパークラスのイニシャライザを呼び出せないことに注意してください。
詳細は、以下の記事を参照してください。
- [Swift] クラスのイニシャライザ3: Designated Initializer と Convenience Initializer の「6. Convenience Initializer は同じクラスのイニシャライザを呼び出すことができる」
Convenience -> Convenience の場合
class Animal {
let name: String
//
// A
//
init(name: String) {
self.name = name
}
//
// B
//
required convenience init() {
self.init(name: "unknown")
}
}
class Cat: Animal {
//
// B をオーバーライド
//
required convenience init() {
//
// スーパークラスから自動的に継承された A を呼び出す(上記の「注意1」「注意2」を参照)
//
self.init(name: "unknown")
}
}
状況2) プロトコルのイニシャライザをオーバーライドするとき
Designated -> プロトコルのイニシャライザの場合
protocol SomeProtocol {
//
// A
//
init()
}
class Animal: SomeProtocol {
//
// A をオーバーライド
//
required init() {
}
}
プロトコルのイニシャライザには、required 修飾子は不要です。
protocol SomeProtocol {
//
// A
//
init()
}
一方で、プロトコルのイニシャライザをオーバーライドするときは、required 修飾子が必要です。
class Animal: SomeProtocol {
//
// A をオーバーライド
//
required init() {
}
}
補足) プロトコルでは、Convenience Initializer を宣言できない
プロトコルでは、convenience initializer を宣言できないことに注意してください。
protocol SomeProtocol {
convenience init() // -> error: convenience initializer not allowed in non-class type
}
Convenience -> プロトコルのイニシャライザの場合
protocol SomeProtocol {
//
// A
//
init(name: String)
}
class Animal: SomeProtocol {
init() {
}
//
// A をオーバーライド
//
required convenience init(name: String) {
self.init()
}
}
補足1) final クラスの場合は、required 修飾子はあってもなくてもいい
protocol SomeProtocol {
//
// A
//
init()
}
final class Animal: SomeProtocol {
//
// A をオーバーライド(required 修飾子はあってもなくてもいい)
//
init() {
}
}
final クラスの場合は、required 修飾子はあってもなくてもかまいません(サブクラスにそのイニシャライザのオーバーライドを強制する必要がないため)。
一方で、final クラスでない場合は、required 修飾子が必要です(サブクラスにそのイニシャライザのオーバーライドを強制する必要があるため)。
protocol SomeProtocol {
//
// A
//
init()
}
class Animal: SomeProtocol {
//
// A'(A をオーバーライド。ここに required 修飾子がないと、サブクラス Cat に、このイニシャライザのオーバーライドを強制できない)
//
required init() {
}
}
class Cat: Animal {
//
// A' をオーバーライド
//
required init() {
}
}
補足2) インスタンスメソッドの場合は、required 修飾子は不要
protocol AnimalProtocol {
//
// A
//
func makeSound()
}
class Cat: AnimalProtocol {
//
// A をオーバーライド(required 修飾子は不要)
//
func makeSound() {
println("Mew")
}
}
補足3) override 修飾子と required 修飾子の両方が必要な場合
スーパークラスとプロトコルのイニシャライザを同時にオーバーライドする場合は、override 修飾子と required 修飾子の両方を付ける必要があります。
protocol SomeProtocol {
init()
}
class Animal {
init() {
}
}
class Cat: Animal, SomeProtocol {
//
// 1. プロトコルのイニシャライザをオーバーライドしているので、required 修飾子が必要
// 2. スーパークラスのイニシャライザもオーバーライドしているので、override 修飾子も必要
//
required override init() {
}
}
override 修飾子と required 修飾子は逆でもかまいません。
class Cat: Animal, SomeProtocol {
//
// override 修飾子と required 修飾子は逆でもかまわない
//
override required init() {
}
}