両者の違い、または便宜上の初期化の目的を理解するのに苦労しています。ありがとう
標準init
:
指定された初期化子は、クラスの主要な初期化子です。指定されたイニシャライザは、そのクラスによって導入されたすべてのプロパティを完全に初期化し、適切なスーパークラスイニシャライザを呼び出して、スーパークラスチェーンまでの初期化プロセスを続行します。
convenience init
:
便利な初期化子はセカンダリであり、クラスの初期化子をサポートします。便利なイニシャライザを定義して、指定されたイニシャライザのパラメータの一部をデフォルト値に設定して、便利なイニシャライザと同じクラスから指定されたイニシャライザを呼び出すことができます。また、特定のユースケースまたは入力値タイプ用にそのクラスのインスタンスを作成するための便利な初期化子を定義することもできます。
基本的にこれは、簡単に言えば、便利なイニシャライザーを使用して、指定されたイニシャライザーをより速く、より便利に呼び出すことです。したがって、便利なイニシャライザーでは、指定されたイニシャライザーのオーバーライドで表示されるself.init
のようなものの代わりにsuper.init
を使用する必要があります。
擬似コードの例:
init(param1, param2, param3, ... , paramN) {
// code
}
// can call this initializer and only enter one parameter,
// set the rest as defaults
convenience init(myParamN) {
self.init(defaultParam1, defaultParam2, defaultParam3, ... , myParamN)
}
主にデフォルトを持つ長い初期化子を使用してカスタムビューなどを作成するときに、これらを頻繁に使用します。ドキュメントは私が説明できるよりも良い説明をします、チェックしてください!
便利な初期化子は、常にすべての変数でウィットを初期化する「痛みを伴う」ようなプロパティを持つクラスがある場合に使用されます。そのため、便利な初期化子で行うことは、オブジェクトを作成し、残りにデフォルト値を割り当てます。レイウェンダリッヒのウェブサイトには非常に優れたビデオがありますが、有料アカウントを持っているので無料かどうかはわかりません。ここに、すべての変数Imでオブジェクトを初期化する代わりに、単にタイトルを付けるだけであることがわかる例を示します。
struct Scene {
var minutes = 0
}
class Movie {
var title: String
var author: String
var date: Int
var scenes: [Scene]
init(title: String, author: String, date: Int) {
self.title = title
self.author = author
self.date = date
scenes = [Scene]()
}
convenience init(title:String) {
self.init(title:title, author: "Unknown", date:2016)
}
func addPage(page: Scene) {
scenes.append(page)
}
}
var myMovie = Movie(title: "my title") // Using convenicence initializer
var otherMovie = Movie(title: "My Title", author: "My Author", date: 12) // Using a long normal initializer
Apple Developer portal から取られた簡単な例です。
基本的に、指定された初期化子はinit(name: String)
であり、保存されているすべてのプロパティが初期化されるようにします。
引数をとらないinit()
簡易イニシャライザーは、指定されたイニシャライザーを使用して、name
格納プロパティの値を[Unnamed]
に自動的に設定します。
class Food {
let name: String
// MARK: - designated initializer
init(name: String) {
self.name = name
}
// MARK: - convenience initializer
convenience init() {
self.init(name: "[Unnamed]")
}
}
// MARK: - Examples
let food = Food(name: "Cheese") // name will be "Cheese"
let food = Food() // name will be "[Unnamed]"
少なくともいくつかのプロパティが保存されている大きなクラスを扱う場合に便利です。 Apple Developer portal。 でオプションと継承についてさらに読むことをお勧めします
注:テキスト全体を読む
指定された初期化子は、クラスの主要な初期化子です。指定された初期化子は、そのクラスによって導入されたすべてのプロパティを完全に初期化し、適切なスーパークラス初期化子を呼び出して、スーパークラスチェーンまで初期化プロセスを続行します。
便利な初期化子はセカンダリであり、クラスの初期化子をサポートします。便利なイニシャライザを定義して、指定されたイニシャライザのパラメータの一部をデフォルトに設定して、便利なイニシャライザと同じクラスから指定されたイニシャライザを呼び出すことができます。
クラスの指定された初期化子は、値型の単純な初期化子と同じ方法で記述されます。
init(parameters) {
statements
}
便利な初期化子は同じスタイルで書かれていますが、initキーワードの前に、スペースで区切られた便利な修飾子があります:
convenience init(parameters) {
statements
}
実用的な例は次のとおりです。
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
let namedMeat = Food(name: "Bacon")
// namedMeat's name is "Bacon”
Foodクラスのinit(name:String)イニシャライザは、指定されたイニシャライザとして提供されます。これは、新しいFoodインスタンスのすべての格納済みプロパティが完全に初期化されるようにするためです。 Foodクラスにはスーパークラスがないため、init(name:String)初期化子は初期化を完了するためにsuper.init()を呼び出す必要はありません。
「Foodクラスは、引数なしの便利な初期化子init()も提供します。 init()初期化子は、名前の値が[Unnamed]であるFoodクラスのinit(name:String)に委任することにより、新しい食品のデフォルトのプレースホルダー名を提供します。
“let mysteryMeat = Food()
// mysteryMeat's name is "[Unnamed]”
階層の2番目のクラスは、RecipeIngredientと呼ばれるFoodのサブクラスです。 RecipeIngredientクラスは、料理のレシピの材料をモデル化します。 (Foodから継承するnameプロパティに加えて)quantityというIntプロパティを導入し、RecipeIngredientインスタンスを作成するための2つの初期化子を定義します。
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
RecipeIngredientクラスには、指定された単一の初期化子init(name:String、quantity:Int)があり、これを使用して新しいRecipeIngredientインスタンスのすべてのプロパティを設定できます。この初期化子は、渡された数量引数を数量プロパティに割り当てることから開始します。これは、RecipeIngredientによって導入された唯一の新しいプロパティです。そうすると、初期化子はFoodクラスのinit(name:String)初期化子まで委任します。
ページ:536抜粋:Apple Inc.「Swiftプログラミング言語(Swift 4)。」iBooks。 https://iTunes.Apple.com/pk/book/the-Swift-programming-language-Swift-4-0-3/id881256329?mt=11
したがって、クラスのすべてのプロパティを指定する必要がない場合に便利です。たとえば、HPの開始値が100のすべてのアドベンチャーを作成する場合、次のconvenience initを使用し、名前を追加するだけです。これにより、コードが大幅に削減されます。
class Adventure {
// Instance Properties
var name: String
var hp: Int
let maxHealth: Int = 100
// Optionals
var specialMove: String?
init(name: String, hp: Int) {
self.name = name
self.hp = hp
}
convenience init(name: String){
self.init(name: name, hp: 100)
}
}
私にとって、convenience initializers
は、クラスプロパティにデフォルト値を設定するだけでなく、もっとやることがある場合に役立ちます。
それ以外の場合は、単にinit
定義にデフォルト値を設定します。例:
class Animal {
var race: String // enum might be better but I am using string for simplicity
var name: String
var legCount: Int
init(race: String = "Dog", name: String, legCount: Int = 4) {
self.race = race
self.name = name
self.legCount = legCount // will be 4 by default
}
}
ただし、単にデフォルト値を設定するだけでなく、それ以外のことも必要になる場合があります。その場合は、convenience initializers
が役立ちます。
extension Animal {
convenience init(race: String, name: String) {
var legs: Int
if race == "Dog" {
legs = 4
} else if race == "Spider" {
legs = 8
} else {
fatalError("Race \(race) needs to be implemented!!")
}
// will initialize legCount automatically with correct number of legs if race is implemented
self.init(race: race, name: name, legCount: legs)
}
}
// default init with all default values used
let myFirstDog = Animal(name: "Bello")
// convenience init for Spider as race
let mySpider = Animal(race: "Spider", name: "Itzy")
// default init with all parameters set by user
let myOctopus = Animal(race: "Octopus", name: "Octocat", legCount: 16)
// convenience init with Fatal error: Race AlienSpecies needs to be implemented!!
let myFault = Animal(race: "AlienSpecies", name: "HelloEarth")