Swift-初期化

Swift 4で宣言されたクラス、構造、列挙は、クラスのインスタンスを準備するために初期化されます。保存されたプロパティの初期値が初期化されます。また、新しいインスタンスの場合も、値が初期化されて先に進みます。初期化関数を作成するためのキーワードは、「init()」メソッドによって実行されます。Swift 4初期化子はObjective-Cとは異なり、値を返しません。その機能は、処理前に新しく作成されたインスタンスの初期化をチェックすることです。Swift 4は、インスタンスの割り当てが解除された後、メモリ管理操作を実行するための「初期化解除」プロセスも提供します。

保存されたプロパティの初期化子の役割

保存されたプロパティは、インスタンスを処理する前に、そのクラスと構造のインスタンスを初期化する必要があります。保存されたプロパティは、初期化子を使用して値を割り当てて初期化し、プロパティオブザーバーを呼び出す必要をなくします。初期化子は保存されたプロパティで使用されます

  • 初期値を作成します。

  • プロパティ定義内でデフォルトのプロパティ値を割り当てる。

  • 特定のデータ型のインスタンスを初期化するには、「init()」を使用します。init()関数内で引数は渡されません。

構文

init() {
   //New Instance initialization goes here
}

struct rectangle {
   var length: Double
   var breadth: Double
   init() {
      length = 6
      breadth = 12
   }
}

var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

area of rectangle is 72.0

ここで、構造体 'rectangle'は、メンバーの長さと幅を 'Double'データ型として初期化されます。Init()メソッドは、新しく作成されたメンバーのlengthとdoubleの値を初期化するために使用されます。長方形の面積は、長方形関数を呼び出すことによって計算され、返されます。

デフォルトでのプロパティ値の設定

Swift 4言語は、保存されたプロパティ値を初期化するためのInit()関数を提供します。また、ユーザーには、クラスまたは構造体のメンバーを宣言するときに、デフォルトでプロパティ値を初期化するためのプロビジョニングがあります。プロパティがプログラム全体で同じ値だけを取る場合、init()で初期化するのではなく、宣言セクションだけで宣言できます。デフォルトでプロパティ値を設定すると、クラスまたは構造体に継承が定義されている場合にユーザーが有効になります。

struct rectangle {
   var length = 6
   var breadth = 12
}

var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

area of rectangle is 72

ここでは、init()で長さと幅を宣言する代わりに、宣言自体で値が初期化されます。

パラメータの初期化

Swift 4言語では、ユーザーは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("area is: \(ar.area)")

let are = Rectangle(fromLeng: 36, fromBread: 12)
print("area is: \(are.area)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

area is: 72.0
area is: 432.0

ローカルおよび外部パラメータ

初期化パラメーターには、関数およびメソッドのパラメーターと同様のローカルパラメーター名とグローバルパラメーター名の両方があります。ローカルパラメーター宣言は初期化本体内にアクセスするために使用され、外部パラメーター宣言はイニシャライザーを呼び出すために使用されます。Swift 4初期化子は、関数およびメソッドの初期化子とは異なり、どの初期化子がどの関数を呼び出すために使用されるかを識別しません。

これを克服するために、Swift 4はinit()のすべてのパラメーターに自動外部名を導入します。この自動外部名は、すべての初期化パラメーターの前に書き込まれるローカル名と同等です。

struct Days {
   let sunday, monday, tuesday: Int
   init(sunday: Int, monday: Int, tuesday: Int) {
      self.sunday = sunday
      self.monday = monday
      self.tuesday = tuesday
   }
   init(daysofaweek: Int) {
      sunday = daysofaweek
      monday = daysofaweek
      tuesday = daysofaweek
   }
}

let week = Days(sunday: 1, monday: 2, tuesday: 3)
print("Days of a Week is: \(week.sunday)")
print("Days of a Week is: \(week.monday)")
print("Days of a Week is: \(week.tuesday)")

let weekdays = Days(daysofaweek: 4)
print("Days of a Week is: \(weekdays.sunday)")
print("Days of a Week is: \(weekdays.monday)")
print("Days of a Week is: \(weekdays.tuesday)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Days of a Week is: 1
Days of a Week is: 2
Days of a Week is: 3
Days of a Week is: 4
Days of a Week is: 4
Days of a Week is: 4

外部名のないパラメーター

初期化アンダースコアに外部名が必要ない場合は、デフォルトの動作を上書きするために「_」が使用されます。

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("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

area is: 180.0
area is: 370.0
area is: 110.0

オプションのプロパティタイプ

あるインスタンスで保存されたプロパティが値を返さない場合、そのプロパティは「オプション」タイプで宣言され、その特定のタイプに対して「値なし」が返されることを示します。保存されたプロパティが「オプション」として宣言されると、初期化自体の間に値が「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("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)

初期化中の定数プロパティの変更

初期化により、ユーザーは定数プロパティの値も変更できます。初期化中、classプロパティを使用すると、そのクラスインスタンスをサブクラスではなくスーパークラスで変更できます。たとえば、前のプログラムで、「length」がメインクラスで「variable」として宣言されているとします。以下のプログラム変数「length」は「constant」変数として変更されています。

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("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)

デフォルトのイニシャライザー

デフォルトの初期化子は、デフォルト値を使用して、基本クラスまたは構造体の宣言されたすべてのプロパティに新しいインスタンスを提供します。

class defaultexample {
   var studname: String?
   var stmark = 98
   var pass = true
}
var result = defaultexample()

print("result is: \(result.studname)")
print("result is: \(result.stmark)")
print("result is: \(result.pass)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます。−

result is: nil
result is: 98
result is: true

上記のプログラムは、クラス名を「defaultexample」として定義されています。3つのメンバー関数は、デフォルトで「スタッド名?」として初期化されます。'nil'値、 'stmark'を98、 'pass'をブール値 'true'として格納します。同様に、クラスのメンバー値は、クラスのメンバータイプを処理する前にデフォルトとして初期化できます。

構造タイプのメンバーごとのイニシャライザー

カスタム初期化子がユーザーによって提供されていない場合、Swift4の構造型は自動的に「メンバーごとの初期化子」を受け取ります。その主な機能は、デフォルトのメンバーごとの初期化を使用して新しい構造インスタンスを初期化することです。次に、新しいインスタンスのプロパティが名前でメンバーごとの初期化に渡されます。

struct Rectangle {
   var length = 100.0, breadth = 200.0
}
let area = Rectangle(length: 24.0, breadth: 32.0)

print("Area of rectangle is: \(area.length)")
print("Area of rectangle is: \(area.breadth)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Area of rectangle is: 24.0
Area of rectangle is: 32.0

構造体は、「長さ」を「100.0」、「幅」を「200.0」として初期化する際に、メンバーシップ関数に対してデフォルトで初期化されます。ただし、変数の長さと幅の処理中に、値は24.0および32.0としてオーバーライドされます。

値型の初期化子委任

イニシャライザ委任は、他のイニシャライザからイニシャライザを呼び出すこととして定義されます。その主な機能は、複数の初期化子間でのコードの重複を回避するための再利用性として機能することです。

struct Stmark {
   var mark1 = 0.0, mark2 = 0.0
}
struct stdb {
   var m1 = 0.0, m2 = 0.0
}

struct block {
   var average = stdb()
   var result = Stmark()
   init() {}
   init(average: stdb, result: Stmark) {
      self.average = average
      self.result = result
   }

   init(avg: stdb, result: Stmark) {
      let tot = avg.m1 - (result.mark1 / 2)
      let tot1 = avg.m2 - (result.mark2 / 2)
      self.init(average: stdb(m1: tot, m2: tot1), result: result)
   }
}

let set1 = block()
print("student result is: \(set1.average.m1, set1.average.m2)
\(set1.result.mark1, set1.result.mark2)")

let set2 = block(average: stdb(m1: 2.0, m2: 2.0),
result: Stmark(mark1: 5.0, mark2: 5.0))
print("student result is: \(set2.average.m1, set2.average.m2)
\(set2.result.mark1, set2.result.mark2)")

let set3 = block(avg: stdb(m1: 4.0, m2: 4.0),
result: Stmark(mark1: 3.0, mark2: 3.0))
print("student result is: \(set3.average.m1, set3.average.m2)
\(set3.result.mark1, set3.result.mark2)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

(0.0,0.0) (0.0,0.0)
(2.0,2.0) 5.0,5.0)
(2.5,2.5) (3.0,3.0)

イニシャライザー委任のルール

値型 クラスタイプ
構造体や列挙型などの値型では、継承はサポートされていません。他の初期化子の参照は、self.initを介して行われます。 継承がサポートされています。保存されているすべてのプロパティ値が初期化されていることを確認します

クラスの継承と初期化

クラスタイプには、定義された格納プロパティが初期値を受け取るかどうかをチェックする2種類の初期化子、つまり指定された初期化子と便利な初期化子があります。

指定イニシャライザーとコンビニエンスイニシャライザー

指定初期化子 コンビニエンスイニシャライザー
クラスのプライマリ初期化と見なされます クラスの初期化をサポートしていると見なされます
すべてのクラスプロパティが初期化され、さらに初期化するために適切なスーパークラス初期化子が呼び出されます 指定された初期化子は、特定のユースケースまたは入力値タイプのクラスインスタンスを作成するために便利な初期化子とともに呼び出されます
クラスごとに少なくとも1つの指定された初期化子が定義されています クラスが初期化子を必要としない場合、便利な初期化子を強制的に定義する必要はありません。
Init(parameters){ステートメント} 便利なinit(パラメータ){ステートメント}

指定イニシャライザーのプログラム

class mainClass {
   var no1 : Int // local storage
   init(no1 : Int) {
      self.no1 = no1 // initialization
   }
}

class subClass : mainClass {
   var no2 : Int // new subclass storage
   init(no1 : Int, no2 : Int) {
      self.no2 = no2 // initialization
      super.init(no1:no1) // redirect to superclass
   }
}

let res = mainClass(no1: 10)
let print = subClass(no1: 10, no2: 20)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

res is: 10
res is: 10
res is: 20

コンビニエンスイニシャライザーのためのプログラム

class mainClass {
   var no1 : Int // local storage
   init(no1 : Int) {
      self.no1 = no1 // initialization
   }
}

class subClass : mainClass {
   var no2 : Int
   init(no1 : Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   // Requires only one parameter for convenient method
   override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

res is: 20
res is: 30
res is: 50

イニシャライザの継承とオーバーライド

Swift 4は、デフォルトでは、サブクラスがメンバータイプのスーパークラス初期化子を継承することを許可していません。継承は、自動初期化子の継承で説明するスーパークラスの初期化子にある程度のみ適用できます。

ユーザーがスーパークラスで初期化子を定義する必要がある場合、初期化子を持つサブクラスは、カスタム実装としてユーザーが定義する必要があります。サブクラスからスーパークラスへのオーバーライドを行う必要がある場合は、「override」キーワードを宣言する必要があります。

class sides {
   var corners = 4
   var description: String {
      return "\(corners) sides"
   }
}

let rectangle = sides()
print("Rectangle: \(rectangle.description)")

class pentagon: sides {
   override init() {
      super.init()
      corners = 5
   }
}

let bicycle = pentagon()
print("Pentagon: \(bicycle.description)")

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Rectangle: 4 sides
Pentagon: 5 sides

指定された便利なイニシャライザーの動作

class Planet {
   var name: String
   init(name: String) {
      self.name = name
   }
   convenience init() {
      self.init(name: "[No Planets]")
   }
}

let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")

let noplName = Planet()
print("No Planets like that: \(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)
   }
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Planet name is: Mercury
No Planets like that: [No Planets]

失敗するイニシャライザー

クラス、構造、または列挙値の定義中に初期化子に障害が発生した場合は、ユーザーに通知する必要があります。変数の初期化は、次の理由で失敗することがあります。

  • 無効なパラメーター値。
  • 必要な外部ソースがない。
  • 初期化が成功しない条件。

初期化メソッドによってスローされた例外をキャッチするために、Swift 4は「failableinitializer」と呼ばれる柔軟な初期化を生成し、構造、クラス、または列挙型メンバーの初期化中に何かが見過ごされていることをユーザーに通知します。失敗する初期化子をキャッチするためのキーワードは「init?」です。また、失敗可能な初期化子と失敗不可能な初期化子を同じパラメータータイプと名前で定義することはできません。

struct studrecord {
   let stname: String
   init?(stname: String) {
      if stname.isEmpty {return nil }
      self.stname = stname
   }
}
let stmark = studrecord(stname: "Swing")

if let name = stmark {
   print("Student name is specified")
}
let blankname = studrecord(stname: "")

if blankname == nil {
   print("Student name is left blank")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Student name is specified
Student name is left blank

列挙型の失敗可能なイニシャライザー

Swift 4言語は、列挙型メンバーが値の初期化をやめたときにユーザーに通知するために、列挙型の失敗可能な初期化子も持つ柔軟性を提供します。

enum functions {
   case a, b, c, d
   init?(funct: String) {
      switch funct {
      case "one":
         self = .a
      case "two":
         self = .b
      case "three":
         self = .c
      case "four":
         self = .d
      default:
         return nil
      }
   }
}
let result = functions(funct: "two")

if result != nil {
   print("With In Block Two")
}
let badresult = functions(funct: "five")

if badresult == nil {
   print("Block Does Not Exist")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

With In Block Two
Block Does Not Exist

クラスの失敗可能なイニシャライザ

列挙型と構造体で宣言されたときに失敗可能な初期化子は、その実装内の任意の状況で初期化の失敗を警告します。ただし、クラスの失敗可能な初期化子は、格納されたプロパティが初期値に設定された後にのみ失敗を警告します。

class studrecord {
   let studname: String!
   init?(studname: String) {
      self.studname = studname
      if studname.isEmpty { return nil }
   }
}

if let stname = studrecord(studname: "Failable Initializers") {
   print("Module is \(stname.studname)")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Module is Optional("Failable Initializers")

失敗可能なイニシャライザーのオーバーライド

初期化の場合と同様に、ユーザーには、サブクラス内のスーパークラスの失敗可能な初期化子をオーバーライドするためのプロビジョニングもあります。スーパークラスの失敗可能な初期化は、サブクラスの失敗不可能な初期化子でオーバーライドすることもできます。

失敗可能なスーパークラス初期化子を失敗不可能なサブクラス初期化子でオーバーライドする場合、サブクラス初期化子はスーパークラス初期化子に委任できません。

失敗しない初期化子は、失敗できる初期化子に委任することはできません。

以下に示すプログラムは、失敗可能なイニシャライザーと失敗できないイニシャライザーについて説明しています。

class Planet {
   var name: String
   
   init(name: String) {
      self.name = name
   }
   convenience init() {
      self.init(name: "[No Planets]")
   }
}
let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")

let noplName = Planet()
print("No Planets like that: \(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)
   }
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Planet name is: Mercury
No Planets like that: [No Planets]

初期化!失敗するイニシャライザー

Swift 4は「init?」を提供します オプションのインスタンスの失敗可能な初期化子を定義します。特定のタイプ「init!」の暗黙的にアンラップされたオプションのインスタンスを定義するには が指定されています。

struct studrecord {
let stname: String

   init!(stname: String) {
      if stname.isEmpty {return nil }
      self.stname = stname
   }
}
let stmark = studrecord(stname: "Swing")

if let name = stmark {
   print("Student name is specified")
}

let blankname = studrecord(stname: "")

if blankname == nil {
   print("Student name is left blank")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Student name is specified
Student name is left blank

必要なイニシャライザー

initialize'required 'キーワードのすべてのサブクラスを宣言するには、init()関数の前に定義する必要があります。

class classA {
   required init() {
      var a = 10
      print(a)
   }
}

class classB: classA {
   required init() {
      var b = 30
      print(b)
   }
}

let res = classA()
let print = classB()

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

10
30
10