97. 可选链(optional chaining)的例子:
class A {
var m : Int = 10
}
class B {
var a : A?
}
class C {
var b : B?
}
var c = C()
var k = c.b?.a?.m
println(k)
上面的例子中,我们在为变量k赋值的时候,使用的是c.b?.a?.m,这里并没有使用c.b!.a!.m,否则由于b或者a是空,会抛出运行时的异常。而使用“?”,会导致返回一个Int?给k,尽管属性“m”的类型是Int,并不是Int?,可选链避免由于元素为nil导致异常的发生。
甚至还可以使用可选链来检测方法是否执行成功,甚至是无返回值的方法(无返回值的方法实际返回的是Void?),如果函数的返回值是nil,则表明函数执行失败,否则表示函数成功执行。
对于下标(subscript)使用可选链,问号要位于下标的中括号前面,例如:
var v = someClassInstance1.subClassInstance1?[0].prop
对于函数使用可选链,问号位于函数圆括号的后面:
var v = someClassInstance1.fun1()?.prop
98. Swift中使用is和as来进行类型转换的判断以及转换。其中as运算符会强制转换为目标类型,如果转换失败会抛异常,所以,如果在不确定转换是否成功的情况下,使用as?运算符,转换失败会返回nil。
99. Swift中的变量绑定会自动将可选类型变量的值解出来,例如:
var i : Int? = 10
var t = (i, 0)
switch t {
case (let m, 0):
println(m)
default:
break
}
例子中常量m直接得到的就是可选类型变量i存储的Int值。
100. Swift中提供AnyObject和Any两种特殊类型,AnyObject可以用来指向任何类的实例,Any可以指向任何类型的实例,除了函数类型。例如:
var a : AnyObject = SomeClass()
var a : Any = 10
101. Swift中可以使用as将数组类型批量做类型转换,例如:
class A {
}
var someObjects : AnyObject[] = [A(), A(), A()]
var arr = someObjects as A[]
102. Swift中允许使用类型嵌套,类型嵌套直接在一个类型定义中嵌套另一个即可:
class A{
class B {
enum C {
case C1, C2, C3
}
}
}
要使用嵌套类型,用类名引用:
var c = A.B.C.C1
103. Swift中通过扩展(extension)来为已知类、结构体或者枚举类型添加功能,类似于Object-C中的category。Swift中的扩展可以添加的内容:
计算属性(get、set方法)和静态计算属性
类方法和实例方法
初始化方法
下标(subscript)
嵌套类型
协议继承关系
104. Swift中扩展使用extension关键字来定义:
extension SomeType {
}
extension SomeType : SomeProtocol {
}
105. Swift中扩展可以添加初始化方法,但是不能添加指派初始化方法,也不能添加析构方法。
106. 在定义类的时候,如果类既有基类,又实现了某些协议(protocol),那么在声明的时候,一定要把基类写在最前面:
class ClassName : BaseClassName, ProtocolName1, Protocol2… {
}
107. Swift中的协议(protocol)可以定义继承类必须实现的属性,属性可以使只读的,也可以是读写的(注意,协议中定义的属性都是用var关键字,静态属性和方法都使用关键字class):
protocol DemoProtocol {
var prop1 : Int { get set }
var prop2 : String { get }
}
虽然在定义的时候使用get/set来指明属性的读写性质,但是实现类中并没有要求一定要定义属性的get和set方法,只要实现类中存在名称相同类型一致的属性即可。要注意的一点限制是:如果协议中定义的属性为读写属性,则实现类中对应属性不能为常量或者只读属性。
108. Swift协议中定义的方法不能指定参数默认值。
109. Swift中协议可以继承其他协议(C#中也可以),语法和类定义类似。
110. 如果需要“一个”类型同时继承多个协议时,可以使用protocol<Protocol1,Protocol2, …>来将多个协议组装成一个整体,例如:
protocol P1 {
}
protocol P2 {
}
protocol P3 {
}
class C1 : P1, P2, P3 {
}
func demoFunc(demoClass : protocol<P1, P2, P3>) {
}
var c = C1()
demoFunc(c)
这种组装只能是临时的一个类型,不能作为一种新的协议类型来定义变量等。
111. 对于协议类型,也可以使用is,as和as?来进行类型判断和类型转换,但是如果想要使用is关键字来判断类型,必须要在protocol关键字前面添加@objc关键字来进行修饰,且使用@objc来修饰的协议不能被结构体和枚举类型继承,as和as?关键字不需要这个要求。例如:
@objc protocol DemoProtocol { }
class A : DemoProtocol { }
class B { }
struct B : DemoProtocol {} //这行编译不过去
var a : AnyObject = A()
var b : AnyObject = B()
var c : Bool = a is DemoProtocol
var d = b as?DemoProtocol //d =nil
注意我们定义变量a的时候特意定义a的类型为AnyObject,如果不这样做,会提示我们“a isDemoProtocol”这句有错误,因为如果a不定义成AnyObject,编译器会推测出a的类型为A,继承DemoProtocol协议,因此a isDemoProtocol这句永远为真,所以会报错来提示我们去掉不必要的语法。
112. 使用@objc关键字定义的协议中可以定义可选(optional)的方法和属性,通过在方法和属性的声明最前面添@optional关键字来实现。例如:
@objc protocol DemoProtocol {
@optional func demoFunc()
@optional var demoProp
}
对于可选的方法和属性,继承类可以选择实现或者不实现。因此,在调用时为了保证程序能正常运行,不会因为方法或者属性没有实现而抛异常,在调用的时候在方法名或者属性后面添加?(和可选链的用法相同)来保证返回可选类型。
113. Swift中的泛型方法定义:
func genericFuncDemo<T>(para1 : T, para2 : T …) {
}
调用的时候很简单,不需要显式地指明T的类型:
var p1 = “abc”
var p2 = “def”
genericFuncDemo(para1 : p1, para2 : p2 …)
可以定义多个占位类型:
func demoFunc<T, U, P>(para1 : T, para2 : U, para3 : P…) {
}
114. Swift中的泛型类、泛型结构体和泛型枚举类型的定义都是在类名和结构体名后面加上<>,里面填写泛型的占位类型,例如上面的T,U,P这些。占位类型的命名最好用大写开头,以表明它是一个类型而非一个值。
115. 可以在定义泛型的时候使用类型约束,例如:
func someFunc<T : SomeClass, U : SomeProtocol>(a : T, b: U) {
}
例如可以定义T继承Equatable,U继承Comparable。
116. Swift中可以为协议定义关联类型,使用typealias关键字来定义关联类型,一个协议中可以定义多个关联类型,例如:
protocol Container {
typealias ItemType
mutating func append(item : ItemType)
var count : Int { get }
subscript(i : Int) -> ItemType { get }
}
上面的关联类型保证了Container中的append方法添加的元素和下标取出的元素类型一致。
下面的结构体实现Container协议中定义的方法,通过typealias ItemType =Int来指定具体的关联类型是Int型:
struct IntStack : Container {
var items = Int[]()
typealias ItemType = Int
mutating func append(item : Int) {
items.append(item)
}
var count : Int {
return items.count
}
subscript(i : Int) -> Int {
return items[i]
}
}
实际上,即使不写typealias ItemType =Int这条语句,Swift也能够推测出ItemType是Int型,编译也能够正常通过,这是因为IntStack中实现了所有Container中定义的方法。
也可以结合泛型和关联类型,例如将上面的IntStack改成泛型结构体。
117. 除了泛型约束之外,还可以使用where子句来对泛型加以约束,例如:
func isAllItemsMatch<C1 : Container, C2 : Container whereC1.ItemType = C2.ItemType, C1.ItemType : Equatable>(someContainer : C1,anotherContainer : C2) -> Bool {
//compare every element in the twocontainers
}
where子句中可以使用and和or来进行逻辑连接。