【学习笔记】SWIFT中的构造函数

2017-05-05 by Liuqingwen | Tags: Swift | Hits

一、前言

2017 年才接触苹果相关的东西,打算学习 Apple iOS 开发,无 Objective-C 基础,目前正在努力学习 SWIFT 的过程中。虽然有一点 Java 基础,不过还是被 SWIFT 这种现代语言震惊了! cold_sweat SWIFT 简洁强大而又人性化,不过最近忙于照顾二崽,学习进度有点慢,也没有任何实操,总感觉很虚,暂时学习到 SWIFT 的构造函数,比起 Java 来说内容要丰富得多,做一个学习笔记,记录要点,掌握精髓,提高自己吧。

我看的是《The Swift Programming Language (Swift 3.0.1)》这本书,官方的作品,目前最新版本 3.1 ,使用 Readiator EPUB Reader 这个 Chrome 扩展应用翻阅的,蛮方便!另外,代码我用 IBM 提供的在线 Swift 代码编写运行交互网站: IBM Swift Sandbox blush

二、语言

  • SWIFT 构造函数基本要点

SWIFT 的构造函数用于结构体、枚举和类中:struct, enum, class ,作为实例的初始化,它的基本语法是 init 函数:

1
2
3
4
5
6
7
8
9
10
class MyClass {
var myProperty = 1
let myVariable:String
init() {
//initialization code here......
myVariable = "abc"
}
}

let instance = MyClass()

你可以不要定义构造函数,比如变量都已经有默认值没有必要自定义构造函数,那么我们可以使用默认构造函数:

1
2
3
4
5
6
7
8
class MyClass {
var myProperty = 1
let myVariable = "abc"
var myOptional:Bool?
//no init() needed here......
}

let instance = MyClass()

比较特别的默认构造函数是对于结构体来说,它有两个默认的构造函数,很人性化:

1
2
3
4
5
6
7
struct AStruct {
var property = 1
var variable = true
}

let twoByTwo = AStruct(property: 2, variable: false)
let twoByTwo = AStruct()

同时对于枚举也有个含有 rawValue 参数的构造函数,仅此一个,注意:这个构造函数还是个可失败构造函数,学过 Java 的朋友都知道,构造函数可以抛出异常,在 Swift 中可以直接让实例化失败返回 nil ,那就是: Failable Initializer 可失败的构造函数:

1
2
3
4
5
6
enum MyEnum: Character {
case avar = "V", alet = "L", afunc = "F"
}
let myFuncEnum = MyEnum(rawValue: "F")
let unknownEnum = MyEnum(rawValue: "X") //Default Failable Initializer......
print(unknownEnum == nil) //true

记住,如果我们手写了构造函数,那么就没有默认构造函数了(注意,手写了 Convenience 便利构造器不算,下文有介绍),对于类和结构体都一样,以下注释部分解除注释运行会报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyClass {
var myProperty = 1
var myVariable:String?
init(_ variable:String) {
//initialization code here......
myVariable = variable
}
}
//let instance = MyClass() //compile-time error!

struct AStruct {
var property = 1
var variable = true
init(){
//initialization code here......
}
}
//let twoByTwo1 = AStruct(property: 2, variable: false) //compile-time error!
  • Override 和 Required 关键字

SWIFT 中类的构造函数在子类中同样定义的话,必须需要 override 关键字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ParentClass {
init() {
//initialization code here......
}
required init(_ param:Int) {
//initialization code here......
}
}

class ChildClass {
override init() {
//initialization code here......
}
required init(_ param:Int) {
//initialization code here......
}
}

如上代码, required 修饰的构造函数在重载时不需要写 override 关键字,但是所有用 required 构造函数在子类中必须全部继承。

另外不得不说说 swift 很符合人类语言特性的超强重构功能: sunglasses

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass {
var myProperty: Int
init(_ digit: Int) {
myProperty = digit
}
init(fromTwoDigits digits: Int) {
myProperty = digits / 10
}
init(fromThreeDigits digits: Int) {
myProperty = digits / 100
}
}
var instance = MyClass(5)
instance = MyClass(fromTwoDigits: 25)
instance = MyClass(fromThreeDigits: 265)
  • Designated 和 Convenience 构造函数

Swift 把构造函数分为 Designated 指定构造函数和 Convenience 便利构造函数,为什么呢?看下面注释部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MyClass {
var myProperty:Int = 1
var myVariable:String?
init(property: Int) {
myProperty = property
}
init(property:Int, variable:String) {
//self.init(property: property) //compile-time error!
}
convenience init() {
self.init(property: 0)
}
convenience init(_ variable:String) {
self.init()
}
}

上面代码中第一个和第二个都是普通指定构造方法,后面两个都是便利构造器,只有便利构造器才能访问指定构造器,而且便利构造器必须访问指定构造器!不管便利构造器是通过直接访问指定构造器还是通过访问其他便利构造器达到访问指定构造器的目的。另外要指出的是,可以直接定义便利构造器,你只需要访问默认的指定构造器就可以了,注意注释部分重复定义的错误提示哦: smiley

1
2
3
4
5
6
7
8
class MyClass5 {
var myProperty:Int = 1
var myVariable:String?
convenience init(_ variable:String) {
self.init()
}
//convenience init() { self.init() } //error: redeclaration of 'init()'
}

另外继承方面的重载很重要,先看下图:

Designated and Convenience initializer delegation

简单的一个原则:要么自动继承,要么在符合“便利访问指定”的约束下重载父类指定构造器,这里代码就有点弱了,直接看官方的一个结构图很容易理解:

Designated and Convenience initializer example

三、总结

相比自己学过的 Java 构造还是有点复杂的,不过也还好,自己总结一下关键点,到时候自己实践的时候遇到问题随时准备查阅吧,毕竟纸上得来终觉浅,绝知此事要躬行!继续努力中~~~ grin

参考资料:
Swift3.0初始化(Initialization): http://www.jianshu.com/p/f334f2c779c4
The Swift Programming Language (Swift 3.1): https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/
IBM Swift Sandbox: https://swift.sandbox.bluemix.net/

PS: (2017-05-15更新)如果类实现了某个定义了构造函数的接口(协议),那么他必须使用 required 关键字,同时符合继承的时候别忘了 override 重载符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// initializer implementation goes here
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// "required" from SomeProtocol conformance;
// "override" from SomeSuperClass
required override init() {
// initializer implementation goes here
}
}

Comments: