📜  Swift-初始化

📅  最后修改于: 2020-12-25 04:37:44             🧑  作者: Mango


在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

在这里,结构“矩形”使用成员的长度和宽度初始化为“双精度”数据类型。 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)

在初始化期间修改常量属性

初始化还允许用户修改常量属性的值。在初始化期间,类属性允许其类实例由超类而不是子类进行修改。例如,在上一个程序中,考虑在主类中将“ 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”定义。默认情况下,三个成员函数被初始化为“ studname?”。存储“ nil”值,“ stmark”为98,“ pass”为布尔值“ true”。同样,可以在处理类成员类型之前将类中的成员值初始化为默认值。

结构类型的成员初始化器

当用户未提供自定义初始化程序时,Swift 4中的Structure类型将自动接收“成员初始化程序”。它的主要函数是使用默认的成员级初始化来初始化新结构实例,然后将新实例属性按名称传递给成员级初始化。

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)

初始化程序委托规则

Value Types Class Types
Inheritance is not supported for value types like structures and enumerations. Referring other initializers is done through self.init Inheritance is supported. Checks all stored property values are initialized

类继承和初始化

类类型具有两种初始化程序,用于检查已定义的存储属性是否接收到初始值,即指定的初始化程序和便捷初始化程序。

指定的初始化程序和便利性初始化程序

Designated Initializer Convenience Initializer
Considered as primary initializes for a class Considered as supporting initialize for a class
All class properties are initialized and appropriate superclass initializer are called for further initialization Designated initializer is called with convenience initializer to create class instance for a specific use case or input value type
At least one designated initializer is defined for every class No need to have convenience initializers compulsory defined when the class does not require initializers.
Init(parameters) { statements } convenience init(parameters) { statements }

指定初始化程序

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生成了一个灵活的初始化,称为“ failable initializer”,以通知用户在初始化结构,类或枚举成员时遗漏了一些东西。捕获失败的初始值设定项的关键字是“ 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