両方の違い、またはの目的を理解するのに苦労していconvenience init
ます。
両方の違い、またはの目的を理解するのに苦労していconvenience init
ます。
回答:
標準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)
}
これらは、主にデフォルトの長い初期化子を持つカスタムビューなどを作成するときによく使用します。ドキュメントは私ができるよりも説明するのに良い仕事をしています、それらをチェックしてください!
コンビニエンスイニシャライザーは、多くのプロパティを持つクラスがある場合に使用され、常にすべての変数でウィットを初期化するのは「苦痛」のようなものです。したがって、コンビニエンスイニシャライザーで行うことは、変数の一部を渡してオブジェクトを作成し、残りをデフォルト値で割り当てます。Ray WenderlichのWebサイトに非常に優れたビデオがありますが、有料アカウントを持っているため、無料かどうかはわかりません。これは、これらすべての変数でオブジェクトを初期化する代わりに、タイトルを付けるだけであることがわかる例です。
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
これは、AppleDeveloperポータルから抜粋した簡単な例です。
基本的に、指定された初期化子はです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]"
少なくともいくつかのプロパティが保存されている大規模なクラスを扱う場合に便利です。AppleDeveloperポータルでオプションと継承についてもう少し読むことをお勧めします。
私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")
便利な初期化子は、クラス拡張で定義できます。しかし、標準的なもの-できません。
ユースケースが同じクラスの別の初期化子の初期化子を呼び出すことである場合は理にかなっています。
遊び場でこれをやってみてください
class Player {
let name: String
let level: Int
init(name: String, level: Int) {
self.name = name
self.level = level
}
init(name: String) {
self.init(name: name, level: 0) //<- Call the initializer above?
//Sorry you can't do that. How about adding a convenience keyword?
}
}
Player(name:"LoseALot")
便利キーワード付き
class Player {
let name: String
let level: Int
init(name: String, level: Int) {
self.name = name
self.level = level
}
//Add the convenience keyword
convenience init(name: String) {
self.init(name: name, level: 0) //Yes! I am now allowed to call my fellow initializer!
}
}
注:テキスト全体を読む
指定初期化子は、クラスの主要な初期化子です。指定された初期化子は、そのクラスによって導入されたすべてのプロパティを完全に初期化し、適切なスーパークラス初期化子を呼び出して、スーパークラスチェーンまで初期化プロセスを続行します。
コンビニエンスイニシャライザはセカンダリであり、クラスのイニシャライザをサポートします。コンビニエンス・イニシャライザーを定義して、コンビニエンス・イニシャライザーと同じクラスから、指定されたイニシャライザーのパラメーターの一部をデフォルトに設定して、指定されたイニシャライザーを呼び出すことができます。
クラスの指定された初期化子は、値型の単純な初期化子と同じ方法で記述されます。
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によって導入された唯一の新しいプロパティであるquantityプロパティに割り当てることから始まります。その後、イニシャライザはFoodクラスのinit(name:String)イニシャライザに委任します。
ページ:536抜粋:Apple Inc.「Swiftプログラミング言語(Swift4)」。iBooks。https://itunes.apple.com/pk/book/the-swift-programming-language-swift-4-0-3/id881256329?mt=11
そのため、クラスのすべてのプロパティを指定する必要がない場合に便利です。したがって、たとえば、HPの値を100から始めてすべての冒険を作成したい場合は、次の便利な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)
}
}
すべての答えは良いように聞こえますが、簡単な例でそれを理解しましょう
class X{
var temp1
init(a: Int){
self.temp1 = a
}
これで、クラスが別のクラスを継承できることがわかりました。
class Z: X{
var temp2
init(a: Int, b: Int){
self.temp2 = b
super.init(a: a)
}
この場合、クラスZのインスタンスを作成するときに、値「a」と「b」の両方を指定する必要があります。
let z = Z(a: 1, b: 2)
ただし、bの値のみを渡し、restで他の値をデフォルト値にする場合は、他の値をデフォルト値で初期化する必要があります。しかし、どのように待つのですか?そのUは、クラスでのみ前にそれを設定する必要があります。
//This is inside the class Z, so consider it inside class Z's declaration
convenience init(b: Int){
self.init(a: 0, b: b)
}
convenience init(){
self.init(a: 0, b: 0)
}
これで、変数に一部、すべて、またはまったく値を指定せずに、クラスZのインスタンスを作成できます。
let z1 = Z(b: 2)
let z2 = Z()