上一章Swift教程请查看:swift类和继承
在Swift中声明的类、结构和枚举将被初始化以准备类的实例。初始值是为存储的属性初始化的,对于新实例也是如此,初始化的值将进一步处理,创建初始化函数的关键字由’init()’方法执行。Swift初始化器不同于Objective-C,它不返回任何值,它的功能是在处理之前检查新创建的实例的初始化,Swift还提供了“析构”过程,用于在实例释放后执行内存管理操作。
存储属性的初始化器角色
存储的属性必须在处理实例之前初始化其类和结构的实例。存储的属性使用初始化器来分配和初始化值,从而消除了调用属性观察者的需要,初始化器用于存储属性:
- 创建初始值。
- 在属性定义中分配默认属性值。
- 要初始化特定数据类型的实例,可以使用“init()”,init()函数中没有传递任何参数。
语法
init() {
//新的实例初始化到这里
}
例子:
struct rectangle {
var length: Double
var breadth: Double
init() {
length = 6
breadth = 12
}
}
var area = rectangle()
print("矩形面积为 \(area.length*area.breadth)")
在这里,结构’rectangle’被成员长度和宽度初始化为’Double’数据类型。Init()方法用于初始化新创建的成员长度和double的值。通过调用矩形函数计算并返回矩形的面积。
默认设置属性值
Swift语言提供Init()函数来初始化存储的属性值。此外,在声明类或结构成员时,用户可以在缺省情况下初始化属性值。当属性在整个程序中单独使用相同的值时,我们可以单独在声明部分声明它,而不是在init()中初始化它。在为类或结构定义继承时,默认设置属性值可使用户启用。
struct rectangle {
var length = 6
var breadth = 12
}
var area = rectangle()
print("面积为 \(area.length*area.breadth)")
这里不是在init()中声明长度和宽度,而是在声明本身中初始化值。
参数初始化
在Swift语言中,用户可以使用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)")
本地及外部参数
初始化参数有本地和全局参数名称类似的功能和方法参数。本地参数声明用于访问初始化的身体内和外部参数声明用于调用初始化。斯威夫特4初始化不同于函数和方法初始化不确定哪些初始化用于调用的函数。
要克服这一点,迅速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("日期: \(week.sunday)")
print("日期: \(week.monday)")
print("日期: \(week.tuesday)")
let weekdays = Days(daysofaweek: 4)
print("日期: \(weekdays.sunday)")
print("日期: \(weekdays.monday)")
print("日期: \(weekdays.tuesday)")
没有外部名称的参数
当初始化不需要外部名称时,使用下划线“_”覆盖默认行为。
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)")
可选的属性类型
当某个实例中存储的属性不返回任何值时,将使用“可选”类型声明该属性,该类型指示为该特定类型返回“无值”。当存储的属性被声明为“可选”时,它会在初始化过程中自动将值初始化为“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)")
在初始化期间修改常量属性
初始化也允许用户修改常量属性的值。在初始化期间,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("面积: \(rectarea.length)")
let rearea = Rectangle(370.0)
print("面积: \(rearea.length)")
let recarea = Rectangle(110.0)
print("面积: \(recarea.length)")
默认的初始值设定项
默认初始化器为基类或结构的所有声明属性提供一个新实例。
class defaultexample {
var studname: String?
var stmark = 98
var pass = true
}
var result = defaultexample()
print("结果: \(result.studname)")
print("结果: \(result.stmark)")
print("结果: \(result.pass)")
上面的程序定义类名为’defaultexample’。三个成员函数在默认情况下被初始化为“studname?”’来存储’nil’值,’stmark’为98,’pass’为布尔值’true’。同样,在处理类成员类型之前,可以将类中的成员值初始化为默认值。
用于结构类型的成员式初始化器
当用户没有提供自定义初始化器时,Swift中的结构类型将自动接收“成员式初始化器”。它的主要功能是用默认的memberwise initialize初始化新结构实例,然后将新实例属性通过名称传递给memberwise initialize。
struct Rectangle {
var length = 100.0, breadth = 200.0
}
let area = Rectangle(length: 24.0, breadth: 32.0)
print("面积: \(area.length)")
print("面积: \(area.breadth)")
默认情况下,在初始化“长度”为“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("结果: \(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("结果: \(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("结果: \(set3.average.m1, set3.average.m2)
\(set3.result.mark1, set3.result.mark2)")
初始化器代理的规则
值类型 | 类类型 |
像结构和枚举这样的值类型不支持继承。引用其他初始化器是通过self.init完成的 | 支持继承,检查所有已存储的属性值是否已初始化 |
类继承和初始化
类类型有两种初始化器,用于检查已定义的存储属性是否接收到初始值,即指定初始化器和便利初始化器。
指定初始化和便利初始化
指定初始化器 | 方便的初始化 |
被认为是类的主要初始化 | 被认为支持类的初始化 |
将初始化所有类属性,并调用适当的超类初始化器进行进一步初始化 | 使用便利初始化器调用指定初始化器,为特定用例或输入值类型创建类实例 |
每个类至少定义一个指定的初始化器 | 当类不需要初始化器时,不需要强制定义便利的初始化器。 |
Init(parameters){语句} | init(parameters){语句} |
指定初始化器程序
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 print = subClass(no1: 10, no2: 20)
print("res: \(res.no1)")
print("res: \(print.no1)")
print("res: \(print.no2)")
程序方便的初始化器
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 print = subClass(no1: 30, no2: 50)
print("res: \(res.no1)")
print("res: \(print.no1)")
print("res: \(print.no2)"
初始化器继承和覆盖
默认情况下,Swift 不允许其子类继承其成员类型的超类初始化器。继承仅在一定程度上适用于超类初始化器,在自动初始化器继承中将对此进行讨论。
当用户需要在超类中定义初始化项时,具有初始化项的子类必须由用户定义为自定义实现。当子类必须重写时,必须声明超类“override”关键字。
class sides {
var corners = 4
var description: String {
return "\(corners) sides"
}
}
let rectangle = sides()
print("矩形: \(rectangle.description)")
class pentagon: sides {
override init() {
super.init()
corners = 5
}
}
let bicycle = pentagon()
print("r: \(bicycle.description)")
指定和方便的初始化实战
class Planet {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[No Planets]")
}
}
let plName = Planet(name: "Mercury")
print("name: \(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)
}
}
Failable可失败初始化器
当定义类、结构或枚举值时发生初始化失败时,必须通知用户,变量的初始化有时会因为以下原因而失败:
- 参数值无效。
- 缺少必要的外部资源。
- 阻止初始化成功的条件。
为了捕获由初始化方法引发的异常,Swift生成了一个名为“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("指定name")
}
let blankname = studrecord(stname: "")
if blankname == nil {
print("留空")
}
枚举的失败初始化器
Swift语言提供了枚举的可失败初始化器的灵活性,当枚举成员没有初始化值时,也可以通知用户。
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("Block Two")
}
let badresult = functions(funct: "five")
if badresult == nil {
print("块不存在")
}
类的失败初始化器
当使用枚举和结构声明时,可失败的初始化程序在其实现中的任何情况下都会发出初始化失败警告。但是,只有在将存储的属性设置为初始值之后,类中的failable初始化器才会发出故障警报。
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)")
}
覆盖一个失败的初始化器
与初始化类似,用户也可以在子类中覆盖超类的可失败初始化器,超类的失败初始化也可以在子类的不可失败初始化器中重写。
当用不可失败的子类初始化重写可失败的超类初始化器时,子类初始化器不能委托到超类初始化器。
不可失败的初始化器永远不能委托给可失败的初始化器。
下面给出的程序描述了可失败和不可失败的初始化程序。
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)
}
}
!init可失败初始化器
Swift提供了“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("指定name")
}
let blankname = studrecord(stname: "")
if blankname == nil {
print("name留空")
}
required初始化器
要声明初始化 ‘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()