スピーディな施工工程
構築プロセスは、クラス、構造体、または列挙型のインスタンスを使用するための準備プロセスです。このプロセスには、インスタンス内の各プロパティの初期値の設定と、必要な準備および初期化タスクの実行が含まれます。
Swift コンストラクターは init() メソッドを使用します。
Objective-C のコンストラクターとは異なり、Swift のコンストラクターは値を返す必要がありません。その主なタスクは、新しいインスタンスが初めて使用される前に適切に初期化されていることを確認することです。
クラス インスタンスは、初期化解除子を定義することで、クラス インスタンスが解放される前にメモリをクリーンアップする作業を実行することもできます。
保存された属性の初期割り当て
クラスと構造体のインスタンスを作成するとき、すべての保存された属性に適切な初期値を設定する必要があります。
保存されたプロパティがコンストラクターで割り当てられると、その値は直接設定され、プロパティ オブザーバーはトリガーされません。
コンストラクターでのストレージプロパティの割り当てプロセス:
初期値を作成します。
属性定義でデフォルトの属性値を指定します。
インスタンスを初期化し、init() メソッドを呼び出します。
コンストラクター
コンストラクターは、特定の型の新しいインスタンスを作成するときに呼び出されます。その最も単純な形式は、パラメータのないインスタンス メソッドに似ており、キーワード init にちなんで名付けられます。
構文
init() { // 实例化后执行的代码 }
例
次の構造は、パラメータなしでコンストラクタinitを定義し、その中で格納されている属性の長さと幅の値を6と12に初期化します:
struct rectangle { var length: Double var breadth: Double init() { length = 6 breadth = 12 } } var area = rectangle() print("矩形面积为 \(area.length*area.breadth)")
上記プログラム実行の出力結果:
矩形面积为 72.0
デフォルトのプロパティ値
同様に、コンストラクターで保存されたプロパティの初期値を設定でき、プロパティの宣言時にデフォルト値を設定することもできます。
デフォルト値を使用すると、コンストラクターをよりシンプルかつ明確にすることができ、プロパティのタイプをデフォルト値から自動的に推測できます。
次の例では、宣言時に属性のデフォルト値を設定します:
struct rectangle { // 设置默认值 var length = 6 var breadth = 12 } var area = rectangle() print("矩形的面积为 \(area.length*area.breadth)")
上記のプログラム実行の出力結果は次のとおりです:
矩形面积为 72
構築パラメータ
を定義するときに構築パラメータを指定できます。コンストラクタ init() は次のように表示されます:
struct Rectangle { var length: Double var breadth: Double var area: Double init(fromLength length: Double, fromBreadth breadth: Double) { self.length = length self.breadth = breadth area = length * breadth } init(fromLeng leng: Double, fromBread bread: Double) { self.length = leng self.breadth = bread area = leng * bread } } let ar = Rectangle(fromLength: 6, fromBreadth: 12) print("面积为: \(ar.area)") let are = Rectangle(fromLeng: 36, fromBread: 12) print("面积为: \(are.area)")
上記のプログラム実行の出力結果は次のとおりです:
面积为: 72.0 面积为: 432.0
内部パラメータ名と外部パラメータ名
は関数やメソッドのパラメータと同じです 内部で使用されるパラメータ名もあります。コンストラクターと、コンストラクターを呼び出すときに使用されるパラメーター名。
ただし、コンストラクターには、関数やメソッドのように括弧の前に区別可能な名前がありません。したがって、コンストラクターを呼び出す場合、呼び出されるコンストラクターは主にコンストラクター内のパラメーターの名前と型によって決まります。
コンストラクターを定義するときにパラメーターの外部名を指定しない場合、Swift は各コンストラクター パラメーターに対して内部名と同じ外部名を自動的に生成します。
struct Color { let red, green, blue: Double init(red: Double, green: Double, blue: Double) { self.red = red self.green = green self.blue = blue } init(white: Double) { red = white green = white blue = white } } // 创建一个新的Color实例,通过三种颜色的外部参数名来传值,并调用构造器 let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) print("red 值为: \(magenta.red)") print("green 值为: \(magenta.green)") print("blue 值为: \(magenta.blue)") // 创建一个新的Color实例,通过三种颜色的外部参数名来传值,并调用构造器 let halfGray = Color(white: 0.5) print("red 值为: \(halfGray.red)") print("green 值为: \(halfGray.green)") print("blue 值为: \(halfGray.blue)")
上記のプログラム実行の出力結果は次のとおりです:
red 值为: 1.0 green 值为: 0.0 blue 值为: 1.0 red 值为: 0.5 green 值为: 0.5 blue 值为: 0.5
外部名パラメーターがありません
コンストラクターのパラメーターに外部名を指定したくない場合は、アンダースコア _
を使用して外部名を表示できます。それを説明しています。
struct Rectangle { var length: Double init(frombreadth breadth: Double) { length = breadth * 10 } init(frombre bre: Double) { length = bre * 30 } //不提供外部名字 init(_ area: Double) { length = area } } // 调用不提供外部名字 let rectarea = Rectangle(180.0) print("面积为: \(rectarea.length)") // 调用不提供外部名字 let rearea = Rectangle(370.0) print("面积为: \(rearea.length)") // 调用不提供外部名字 let recarea = Rectangle(110.0) print("面积为: \(recarea.length)")
上記のプログラムの実行の出力結果は次のとおりです:
面积为: 180.0 面积为: 370.0 面积为: 110.0
オプションの属性タイプ
カスタマイズしたタイプに、論理的に null 値を許可する格納された属性が含まれている場合は、それをオプションのタイプ (オプションの属性タイプ) として定義する必要があります。
保存されたプロパティがオプションとして宣言されると、自動的に空の nil に初期化されます。
struct Rectangle { var length: Double? init(frombreadth breadth: Double) { length = breadth * 10 } init(frombre bre: Double) { length = bre * 30 } init(_ area: Double) { length = area } } let rectarea = Rectangle(180.0) print("面积为:\(rectarea.length)") let rearea = Rectangle(370.0) print("面积为:\(rearea.length)") let recarea = Rectangle(110.0) print("面积为:\(recarea.length)")
上記のプログラムの実行の出力結果は次のとおりです:
面积为:Optional(180.0) 面积为:Optional(370.0) 面积为:Optional(110.0)
構築中に定数属性を変更する
構築プロセスの終了前に定数の値が決定できる限り、値を変更できます構築プロセス中の任意の時点での定数属性の。
クラス インスタンスの場合、その定数属性は、それを定義するクラスの構築プロセス中にのみ変更できます。サブクラス内では変更できません。
length プロパティは定数になりましたが、引き続きそのクラスのコンストラクターでその値を設定できます:
struct Rectangle { let length: Double? init(frombreadth breadth: Double) { length = breadth * 10 } init(frombre bre: Double) { length = bre * 30 } init(_ area: Double) { length = area } } let rectarea = Rectangle(180.0) print("面积为:\(rectarea.length)") let rearea = Rectangle(370.0) print("面积为:\(rearea.length)") let recarea = Rectangle(110.0) print("面积为:\(recarea.length)")
上記のプログラム実行の出力は次のとおりです:
面积为:Optional(180.0) 面积为:Optional(370.0) 面积为:Optional(110.0)
デフォルト コンストラクター
デフォルト コンストラクターは単純にすべての属性値がデフォルト値に設定されているインスタンス:
次の例では、ShoppingListItem クラスのすべての属性がデフォルト値を持ち、親クラスのない基本クラスのデフォルト値を自動的に取得します。すべての属性のデフォルトのコンストラクター
class ShoppingListItem { var name: String? var quantity = 1 var purchased = false } var item = ShoppingListItem() print("名字为: \(item.name)") print("数理为: \(item.quantity)") print("是否付款: \(item.purchased)")
上記のプログラム実行の出力は次のとおりです:
名字为: nil 数理为: 1 是否付款: false
構造体のメンバーごとの初期化子
構造体がすべての格納されたプロパティにデフォルト値を提供し、カスタマイズされた初期化子を提供しない場合、メンバーごとのコンストラクターを自動的に取得できます。
メンバーごとのコンストラクターを呼び出すときは、メンバー属性名と同じパラメーター名を渡して、メンバー属性の初期割り当てを完了します。
次の例では、長さと幅の 2 つの属性を含む構造体 Rectangle を定義します。 Swift は、100.0 と 200.0 の初期割り当てに基づいて、これら 2 つのプロパティの Double 型を自動的に推測できます。
struct Rectangle { var length = 100.0, breadth = 200.0 } let area = Rectangle(length: 24.0, breadth: 32.0) print("矩形的面积: \(area.length)") print("矩形的面积: \(area.breadth)")
両方の格納プロパティにデフォルト値があるため、構造体 Rectangle はメンバーごとのコンストラクター init(width:height:) を自動的に取得します。 これを使用して Rectangle の新しいインスタンスを作成できます。
上記のプログラムの実行出力は次のとおりです:
名字为: nil 矩形的面积: 24.0 矩形的面积: 32.0
値型のコンストラクター プロキシ
コンストラクターは、他のコンストラクターを呼び出すことで、インスタンスの構築プロセスの一部を完了できます。このプロセスはコンストラクターの委任と呼ばれ、複数のコンストラクター間でのコードの重複を削減します。
次の例では、Rect 構造体が Size と Point の構築プロセスを呼び出します:
struct Size { var width = 0.0, height = 0.0 } struct Point { var x = 0.0, y = 0.0 } struct Rect { var origin = Point() var size = Size() init() {} init(origin: Point, size: Size) { self.origin = origin self.size = size } init(center: Point, size: Size) { let originX = center.x - (size.width / 2) let originY = center.y - (size.height / 2) self.init(origin: Point(x: originX, y: originY), size: size) } } // origin和size属性都使用定义时的默认值Point(x: 0.0, y: 0.0)和Size(width: 0.0, height: 0.0): let basicRect = Rect() print("Size 结构体初始值: \(basicRect.size.width, basicRect.size.height) ") print("Rect 结构体初始值: \(basicRect.origin.x, basicRect.origin.y) ") // 将origin和size的参数值赋给对应的存储型属性 let originRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0)) print("Size 结构体初始值: \(originRect.size.width, originRect.size.height) ") print("Rect 结构体初始值: \(originRect.origin.x, originRect.origin.y) ") //先通过center和size的值计算出origin的坐标。 //然后再调用(或代理给)init(origin:size:)构造器来将新的origin和size值赋值到对应的属性中 let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0)) print("Size 结构体初始值: \(centerRect.size.width, centerRect.size.height) ") print("Rect 结构体初始值: \(centerRect.origin.x, centerRect.origin.y) ")
上記プログラムの実行出力は次のとおりです:
Size 结构体初始值: (0.0, 0.0) Rect 结构体初始值: (0.0, 0.0) Size 结构体初始值: (5.0, 5.0) Rect 结构体初始值: (2.0, 2.0) Size 结构体初始值: (3.0, 3.0) Rect 结构体初始值: (2.5, 2.5)
Constructor プロキシ ルール
Value type | Class type |
---|---|
継承はサポートされていないため、コンストラクター委任のプロセスは比較的単純です。コンストラクターは、自身が提供する他のコンストラクターにのみ委任できるためです。 self.init を使用すると、カスタム コンストラクター内で同じ値型の他のイニシャライザーを参照できます。 | 他のクラスから継承できます。つまり、クラスは、継承されたすべての格納プロパティが構築中に正しく初期化されるようにする責任があります。 |
クラスの継承と構築プロセス
Swift は、すべてのクラス インスタンスに格納されているプロパティが初期値を取得できるようにするために、指定されたイニシャライザーとコンビニエンス イニシャライザーの 2 種類のクラス コンストラクターを提供します。
指定されたコンストラクター | 便利なコンストラクター |
クラスで最も重要なコンストラクター | クラスの二次および補助コンストラクター |
クラスで提供されるすべてのプロパティを初期化し、クラスのコンストラクターを呼び出します親クラスチェーンに従って親クラスを上位に移動し、親クラスの初期化を実装します。 | 便利なイニシャライザは、同じクラス内の指定されたコンストラクタを呼び出し、そのパラメータのデフォルト値を提供するように定義できます。便利な初期化子を定義して、特別な目的または特定の入力を使用してインスタンスを作成することもできます。 |
すべてのクラスには少なくとも 1 つの指定されたイニシャライザが必要です | 必要な場合にのみクラスに便利なイニシャライザを提供します |
Init(parameters) { statements } | convenience init(parameters) { statements } |
指定されたコンストラクターインスタンス
class mainClass { var no1 : Int // 局部存储变量 init(no1 : Int) { self.no1 = no1 // 初始化 } } class subClass : mainClass { var no2 : Int // 新的子类存储变量 init(no1 : Int, no2 : Int) { self.no2 = no2 // 初始化 super.init(no1:no1) // 初始化超类 } } let res = mainClass(no1: 10) let res2 = subClass(no1: 10, no2: 20) print("res 为: \(res.no1)") print("res2 为: \(res2.no1)") print("res2 为: \(res2.no2)")
上記プログラムの実行の出力結果は次のとおりです:
res 为: 10 res 为: 10 res 为: 20
コンビニエンスコンストラクターインスタンス
class mainClass { var no1 : Int // 局部存储变量 init(no1 : Int) { self.no1 = no1 // 初始化 } } class subClass : mainClass { var no2 : Int init(no1 : Int, no2 : Int) { self.no2 = no2 super.init(no1:no1) } // 便利方法只需要一个参数 override convenience init(no1: Int) { self.init(no1:no1, no2:0) } } let res = mainClass(no1: 20) let res2 = subClass(no1: 30, no2: 50) print("res 为: \(res.no1)") print("res2 为: \(res2.no1)") print("res2 为: \(res2.no2)")
上記のプログラムの実行の出力結果は次のとおりです:
res 为: 20 res2 为: 30 res2 为: 50
コンストラクターの継承とオーバーロード
Swift のサブクラス 親クラスのコンストラクターはデフォルトでは継承されません。
親クラスのコンストラクターは、確実で安全な場合にのみ継承されます。
親クラスで指定されたコンストラクターをオーバーライドする場合は、オーバーライド修飾子を記述する必要があります。
class SuperClass { var corners = 4 var description: String { return "\(corners) 边" } } let rectangle = SuperClass() print("矩形: \(rectangle.description)") class SubClass: SuperClass { override init() { //重载构造器 super.init() corners = 5 } } let subClass = SubClass() print("五角型: \(subClass.description)")
上記のプログラム実行の出力結果は次のとおりです:
矩形: 4 边 五角型: 5 边
指定コンストラクターとコンビニエンスコンストラクターのインスタンス
以下の例は、動作中の指定コンストラクター、コンビニエンスイニシャライザー、および自動コンストラクターの継承を示します。
これは、MainClass と SubClass の 2 つのクラスを含むクラス階層を定義し、それらのコンストラクターがどのように相互作用するかを示します。
class MainClass { var name: String init(name: String) { self.name = name } convenience init() { self.init(name: "[匿名]") } } let main = MainClass(name: "php") print("MainClass 名字为: \(main.name)") let main2 = MainClass() print("没有对应名字: \(main2.name)") class SubClass: MainClass { var count: Int init(name: String, count: Int) { self.count = count super.init(name: name) } override convenience init(name: String) { self.init(name: name, count: 1) } } let sub = SubClass(name: "php") print("MainClass 名字为: \(sub.name)") let sub2 = SubClass(name: "php", count: 3) print("count 变量: \(sub2.count)")
上記のプログラム実行の出力結果は次のとおりです:
MainClass 名字为: php 没有对应名字: [匿名] MainClass 名字为: php count 变量: 3
クラスのFailableコンストラクター
クラス、構造体、または列挙型オブジェクトがそれ自体の構築プロセスで失敗する可能性がある場合は、Failableコンストラクターを定義します。
変数の初期化が失敗する考えられる理由は次のとおりです:
無効なパラメータ値が渡されました。
何らかの必要な外部リソースが不足しています。
特定の条件が満たされていません。
この建設プロセス中に失敗する可能性のある状況に適切に対処するため。
クラス、構造体、または列挙型の定義に 1 つ以上の失敗可能な初期化子を追加できます。構文は、init キーワードの後に疑問符 (init?) を追加することです。
例
次の例では、Animal という名前の構造体が定義されており、これには、species という名前の String 型の定数属性があります。
同時に、この構造体は String 型パラメーター種を持つ失敗可能なコンストラクターも定義します。この失敗可能なイニシャライザは、受信パラメータが空の文字列であるかどうかを確認するために使用されます。空の文字列の場合、失敗可能なイニシャライザはオブジェクトの構築に失敗します。それ以外の場合は、成功します。
struct Animal { let species: String init?(species: String) { if species.isEmpty { return nil } self.species = species } } //通过该可失败构造器来构建一个Animal的对象,并检查其构建过程是否成功 // someCreature 的类型是 Animal? 而不是 Animal let someCreature = Animal(species: "长颈鹿") // 打印 "动物初始化为长颈鹿" if let giraffe = someCreature { print("动物初始化为\(giraffe.species)") }
上記のプログラム実行の出力結果は次のとおりです:
动物初始化为长颈鹿
列挙型の失敗可能な初期化子
1 つ以上のパラメーターを使用して失敗可能な初期化子を構築することで、列挙型の特定の列挙メンバーを取得できます。
例
次の例では、TemperatureUnit という名前の列挙型が定義されています。これには、3 つの可能な列挙メンバー (ケルビン、摂氏、華氏) と、Character 値に対応する列挙メンバーを見つけるために使用される失敗可能な初期化子が含まれています:
enum TemperatureUnit { // 开尔文,摄氏,华氏 case Kelvin, Celsius, Fahrenheit init?(symbol: Character) { switch symbol { case "K": self = .Kelvin case "C": self = .Celsius case "F": self = .Fahrenheit default: return nil } } } let fahrenheitUnit = TemperatureUnit(symbol: "F") if fahrenheitUnit != nil { print("这是一个已定义的温度单位,所以初始化成功。") } let unknownUnit = TemperatureUnit(symbol: "X") if unknownUnit == nil { print("这不是一个已定义的温度单位,所以初始化失败。") }
上記のプログラム実行の出力は次のとおりです:
这是一个已定义的温度单位,所以初始化成功。 这不是一个已定义的温度单位,所以初始化失败。
失敗可能な初期化子値型 (構造体や列挙型など) の失敗可能な初期化子には、構築失敗がいつ、どこでトリガーされるかについての制限はありません。
ただし、クラスの失敗可能な初期化子は、すべてのクラス属性が初期化され、すべてのクラス間のコンストラクター間のプロキシ呼び出しが発生した後にのみ、失敗動作をトリガーできます。
例
次の例では、StudRecord という名前のクラスが定義されています。studname 属性は定数であるため、StudRecord クラスが正常に構築されると、studname 属性は非 nil 値を持つ必要があります。
class StudRecord { let studname: String! init?(studname: String) { self.studname = studname if studname.isEmpty { return nil } } } if let stname = StudRecord(studname: "失败构造器") { print("模块为 \(stname.studname)") }
上記のプログラムの実行の出力結果は次のとおりです:
模块为 失败构造器
失敗可能なコンストラクターのオーバーライド
他のコンストラクターと同様に、基本クラスの失敗可能なコンストラクターをサブクラスの失敗可能なコンストラクターでオーバーライドすることもできます。
あるいは、基本クラスの失敗可能なイニシャライザをサブクラスの失敗しないイニシャライザでオーバーライドすることもできます。
失敗可能なイニシャライザを失敗しないイニシャライザでオーバーライドすることはできますが、その逆は機能しません。
失敗しないイニシャライザは、失敗可能なイニシャライザに委任することはできません。
例
次の例では、失敗可能なコンストラクターと失敗不可能なコンストラクターについて説明します:
class Planet { var name: String init(name: String) { self.name = name } convenience init() { self.init(name: "[No Planets]") } } let plName = Planet(name: "Mercury") print("行星的名字是: \(plName.name)") let noplName = Planet() print("没有这个名字的行星: \(noplName.name)") class planets: Planet { var count: Int init(name: String, count: Int) { self.count = count super.init(name: name) } override convenience init(name: String) { self.init(name: name, count: 1) } }
上記のプログラム実行の出力結果は次のとおりです:
行星的名字是: Mercury 没有这个名字的行星: [No Planets]
失敗可能なコンストラクター init!
一般的に、init キーワードの後に渡します。疑問符 (init?) を追加すると失敗可能なイニシャライザを定義できますが、init の後に感嘆符を追加することで失敗可能なイニシャライザを定義することもできます (init!)。例は次のとおりです。
struct StudRecord { let stname: String init!(stname: String) { if stname.isEmpty {return nil } self.stname = stname } } let stmark = StudRecord(stname: "php") if let name = stmark { print("指定了学生名") } let blankname = StudRecord(stname: "") if blankname == nil { print("学生名为空") }
上記プログラムの実行の出力結果は次のとおりです。
指定了学生名 学生名为空