Swiftクラスでのrequired
キーワードの使用を理解しようとしています。
class SomeClass
{
required init() {
// initializer implementation goes here
}
}
required
は、子クラスにメソッドを実装することを強制しません。親クラスのrequired
指定初期化子をオーバーライドする場合は、required
ではなくoverride
を記述する必要があります。私はそれがどのように機能するかを知っていますが、なぜこれをするべきか理解できません。
required
の利点は何ですか?私が知る限り、C#のような言語にはこのようなものはなく、override
で問題なく動作します。
実際には、このクラスがサブクラスを持っている場合、それらがこの同じ初期化子を継承または実装することを保証するためにコンパイラを満足させる方法にすぎません。 サブクラスがそれ自体の指定された初期化子を持っている場合、スーパークラスの初期化子は継承されないというルールのため、この点には疑問があります。したがって、スーパークラスが初期化子を持ち、サブクラスnotを持つことが可能です。 required
はその可能性を克服します。
コンパイラがこの方法で満たされる必要がある1つの状況は、プロトコルに関係し、次のように機能します。
_protocol Flier {
init()
}
class Bird: Flier {
init() {} // compile error
}
_
問題は、Birdにサブクラスがある場合、そのサブクラスはinit
を実装または継承する必要があり、それを保証していないことです。 Birdのinit
をrequired
としてマークすると、保証されます。
別の方法として、Birdをfinal
としてマークし、逆を保証します。つまり、サブクラスを持たないようにします。
別の状況では、同じ初期化子を呼び出すことでクラスまたはそのサブクラスを作成できるファクトリメソッドがあります。
_class Dog {
var name: String
init(name: String) {
self.name = name
}
}
class NoisyDog: Dog {
}
func dogMakerAndNamer(whattype: Dog.Type) -> Dog {
let d = whattype.init(name: "Fido") // compile error
return d
}
_
dogMakerAndNamer
は、DogまたはDogサブクラスでinit(name:)
初期化子を呼び出しています。しかし、サブクラスにinit(name:)
初期化子があることをコンパイラーがどのように確認できますか? required
の指定は、コンパイラーの不安を和らげます。
Mattが上記で与えたものとは別に、Required
によって提供される別のソリューションに注意を喚起したいと思います。
_class superClass{
var name: String
required init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
}
let instanceSubClass = subClass()
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Subclass Untitled"
_
上記の例で確認できるように、superClass
でrequired init()
を宣言し、subClass
でsuperClassのinit()
初期化子がデフォルトで継承しているので、subClass let instanceSubClass = subClass()
。
ただし、サブクラスに指定された初期化子を1つ追加して、実行時の値をストアドプロパティneakName
に割り当てるとします。もちろん追加することはできますが、その結果、superClassの初期化子はsubClassに継承されません。したがって、subClass
のインスタンスを作成する場合は、以下のように、独自の指定イニシャライザーを使用して作成します。
_class superClass{
var name: String
init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
init(neakName: String) {
self.neakName = neakName
}
}
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Bobby"
_
上記では、subClass()
だけではsubClass
のインスタンスを作成できません。ただし、ただし、superClassのすべてのサブクラスに独自のinit()
初期化子が必要な場合subClass()
によって直接インスタンスを作成します。スーパークラスのinit()
の前にrequired
キーワードを置くだけで、subClass
にもinit()
初期化子を追加するよう強制されます-以下のように。
_class superClass{
var name: String
required init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
init(neakName: String) {
self.neakName = neakName
}
} // Compiler error <------------ required `init()` must be provided by subClass.
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Bobby"
_
SO、すべてのサブクラスをスーパークラスの_required initializer
_で実装する必要がある場合、スーパークラスの初期化子の前にrequired
キーワードを使用します。
ドキュメント によると:
Write the required modifier before the definition of a class initializer to
indicate that every subclass of the class must implement that initializer
はい、必須です。すべての子クラスにこのコンストラクターを強制的に実装させます。ただし、これは必要ありません
if you can satisfy the requirement with an inherited initializer.
したがって、親コンストラクタで完全に初期化できないより複雑なクラスを作成した場合、requireコンストラクタを実装する必要があります。
ドキュメントからの例(いくつか追加されたものを含む):
class SomeClass {
required init() {
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
let thisNeedsToBeInitialized: String
required init() {
// subclass implementation of the required initializer goes here
self.thisNeedsToBeInitialized = "default value"
}
}
サブクラスに独自の初期化子を追加しようとする場合、スーパークラスで宣言された特定の事項に従う必要があります。そのため、必要なメソッドを実装することを忘れないようにしてください。コンパイラを忘れると、エラー// fatal error, we've not included the required init()
が表示されます。もう1つの理由は、サブクラスが独自の初期化子を定義しているときにサブクラスが従う必要がある一連の条件を作成することです。