1. Deinitialization
1.在对象被销毁之前立即执行,不允许自己手动调用,只适用于Class.
2.一个类最多只有一个deinit方法 ,并且没有圆括号
3.父类的deinitializers会被它的子类们继承,而且父类的deinitializers会在子类的deinitializers实现的最后被调用.即使子类没有提供deinitializers,父类的deinitializers也会被调用.
4.由于Swift会自动帮你管理实例内存,一般情况下用不到deinitializers.但是有一些情景需要用到,比如:打开了一个文件,这时候需要自己手动关闭 释放内存.
2.Automatic Reference Counting (ARC)
1.怎么工作的? 其实就是引用计数
2.强引用循环解决方法:
1.weak references
1.当引用的对象可能nil,使用 weak 修饰,不强引用对象
2.weak修饰的引用必须是变量不能是常量.指示它们的值可以改变.
3.weak修饰的引用最好是optional的
4.当引用的对象的引用计数为0的时候,对象会被释放,然后reference会被置为nil
2.unowned reference
1.当引用对象永远都会有值(非nil)的时候,用unowned修饰,不强引用对象,
2.unowned修饰的引用必须是 non-optional的.
3.当引用的对象的引用计数为0的时候,对象会被释放,但是reference不会被置为nil.当用reference去访问被释放的对象时,会产生运行时错误,所以用unowned reference的时候请一定要保证unowned reference的时候 对象一定不会为nil
3.unowned reference和Implicitly Unwrapped Optional (!) 一起使用
当两边一定都有值(非nil),一边使用unowned一边使用 !
3. Closures的强引用循环解决
1.产生场景: 当闭包作为property被对象保存.但是在闭包的使用过程中,访问了对象属性,比如self. self.someProperty,调用了对象方法,比如self.someMethod().在这些情况下,闭包都会捕捉 self,造成了一个强引用循环.(闭包也是reference type)
注意:在这个产生情景中,如果闭包属性是在声明的时候就保存,闭包的property应该被声明为 lazy,否则无法访问self.由于它是lazy,直到它被真正调用,都不会被初始化,也就意味着在闭包属性初始化的时候,对象其他property一定已经初始化好了,而且self已经存在了.
2.用 capture list (捕捉列表) 解决
lazy var someClosure: (Int, String) -> String = {
可以使用unowned/weak 来修饰,用逗号来分割.什么时候用unowned 什么时候用weak?和前面说的一样.
NOTE:Swift要求你在调用实例方法的时候,使用sef.xxxMethod().这样能让你意识到你引用了self.这帮助你意识到可能在闭包中意外地捕获了self.
3.Optional Chaining (这里感觉表达的不是很好,可以去看下官方文档.)
1当调用properties,methods和subscrips的时候,无论properties是否是optional,无论methods和subscrips返回的值是否是optional.Optional Chaining都会返回一个 optional的结果(type一样,只是会被包装成optional).一整个调用链条都会影响.
2.使用方法:用 ? 放在后面.
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
let roomCount = john.residence?.numberOfRooms (返回的numberOfRooms会是Int?类型,结果:let roomCount 为nil)
let roomCount = john.residence!.numberOfRooms (直接报出运行时错误)
Optional Chaining比 一般的 失败的时候更优雅.
3.可以使用Optional Chaining 来调用一个optional value身上的方法来检查这个方法是否调用成功,你可以这么做,即使这个方法并没有任何返回值. 实际上没有返回值的方法返回void,而在Optional Chaining中,返回 void?
if john.residence?.printNumberOfRooms() != nil {
print("It was possible to print the number of rooms.")
} else {
print("It was not possible to print the number of rooms.")
}
同理,设置property的时候, 其实setProperty. 也是可以检查是否设置属性成功
if (john.residence?.address = someAddress) != nil {
print("It was possible to set the address.")
} else {
print("It was not possible to set the address.")
}
4.john.residence?[0].name
5.注意: john.residence?.address?.buildingIdentifier()?.hasPrefix("The") ?在()后面,Optional Chaining链着的是方法的返回值,而不是方法本身.
4.Error Handling (错误处理)
1.错误类型必须是 value types(errors are represented by values of types),并且必须要遵守ErorrType协议,一般是用枚举比较好
2.方法/函数可以抛出Error,用关键字 throws
func canThrowErrors throws -> String{}
3.调用 可能会抛出异常的函数时 在前面必须加 try关键字
4.处理异常:
do {
try XXXXXX()
XXXXXXXX
defer{
//defer的代码在外面代码块完成后执行
}
}catch XXXXX{
// TODO
}
5.可以用 try! 调用可能会抛出异常的函数,一旦函数抛出异常,直接产生运行时错误.
5.guard
1.guard的格式和if非常的像:
guard var a = inventory[name] else{
//当a为nil时,执行这段代码,可选择抛出异常.
}
guard a>b else{
//当a>b不成立时,执行这段代码,可选择抛出异常.
}
2.含义:守卫 使用guard,表示后面的条件一定为真/一定不为nil.
3.guard后面一定会跟else.当guard后面的条件为true/为nil 那么else里面的语句会被执行
4.guard后面若是一个声明赋值语句.那么声明的变量/常量可以在后面继续使用.相反,if中的只能在if的代码块里面执行.
6.defer
1.defer的代码延迟执行,直到当前所在的代码块结束才执行.
2.defer的代码不能包括break, return等transfer control.
3.在一个代码块中,如果有多个defer,先出现的defer后执行.
7.Type Casting
1.类型检查:用 is 关键字来判断某个对象是不是某个类的实例
2.向下转型: 用 as? 或 as! 关键字
1.as? 返回的是一个 optional value. 如果向下转型失败,value为nil
2.as! 返回的是一个 implicitly unwrapped value.如果向下转型失败,直接报运行时错误.
3.如: let movie = item as? Movie;
3.AnyObject : 可以表示 任何类的一个对象,意味着可以指向任何对象
1.为什么会有这东西? 调用Cocoa APIs的时候,经常会得到一个[AnyObject]的数组.这是因为在OC里面数组是没有类型的(存放的全是NSObject).
2.一般取出数组中的元素 然后用as向下转型.
3.当你确定一个数组里面全部都是某个类的对象.那么可以使用一个简单的方式直接把数组向下转型成有类型的数组:
for movie in someObjects as! [Movie] {
//TODO
}
4.Any :
1.可以表示任何类型的实例 包括基本数据类型,枚举,结构体,函数,闭包等等. var things = [Any]() (things是一个数组)
2.可以用switch来安全地拿出数组中不同类型的元素进行不同的操作:
8. ?? (Nil Coalescing Operator)
形式 : let var c = a ?? b.
1.a必须是optional value
2.b必须和a的type相同
3.当a为nil,返回b.当a不为nil,返回a
4.当a不为nil,直接返回a,b不会执行!
5.这个式子是 let var c = a!=nil ? a : b 的简写!
用处: 比如当a为nil的时候,可以给c赋值一个默认值b.
9.Nested Types
Swift 允许你在 structure class enumeration的实现中嵌套structure class enumeration. 你可以嵌套无限层,没有限制
10.Extensions
1.Extensions可以添加新功能到已经存在的class,structure,enumeration,protocal上.这能够让你扩展那些你并不能接触到源代码的types.Extensions很像OC中的Category,但并不是Category,因为Extension没有名字
2.定义 : (后面的协议是可选的)
extension SomeType: SomeProtocol, AnotherProtocol {
// implementation of protocol requirements goes here
}
3.Extension能做到的:
1.添加computed properties 和 computed type properties (? : type嘛!! 就是 type properties......)
不能添加 stored properties和 property observers
2.定义instance method 和 type method (注意给enumeration和structure添加方法的时候要注意,如果方法中修改了self,或者修改了他们的property,要在方法前添加 mutating 关键字)
3.提供新的构造方法
4.定义 下标方法
5.定义和使用新的嵌套类型(nested types)
6.让一个已经存在的type去遵守一个协议
注意:Extension并不能重写那些已经存在的功能,只能新增.
4.如果你给一个type定义了一个extension.那么这个type的实例将会拥有extension所提供的扩展功能.即使这个实例在extension被定义之前已经存在.
5.可以给class新增convenience initializer,但是不能新增designated initializers. designated和deinitializer必须是由源class提供.
6.如果给value types提供一个新的initializer.并且这个type的每个stored properties都有默认值,且type原来没有定义任何initializer,那么在这个新的initializer里面,可以调用type的 default initializer和memberwise initializer
11.Protocols
1.定义 .可以定义 methods,properties等等,并且默认是强制性要求遵守该协议的类型实现所有功能,也可以使用optional来定义可选的功能
2.使用:
1.应用到structure和enumeration 没什么好说的
2.应用到class的时候有点特殊,因为class可能继承自其他类.所以当class有父类的话,父类必须出现在protocol前面,用逗号隔开
3.定义property(或 type property):
1. 需定义 name 和 type 还有这个property是gettable还是gettable且settable.不要求 遵守该协议的类型 定义该property的时候一定是stored还是computed. 同样遵守只能大 不能小的规则(具体你懂的)
2.property必须是var. 并且至少带有一个gettable.
3.定义成type property的时候,必须使用 static 关键字而不是class
4.如: var mustBeSettable: Int { get set }
4.定义method
1.和普通的method定义相同,除了没有{}和方法体.并且形参不能带有default value. inout形参可以.(提个醒:下标方法中,参数不能有默认值且inout形参也不行)
2.定义成type method的时候,必须使用 static 关键字而不是class
3.若方法中可能要修改了self,或者可能要修改他们的property,要在方法前添加 mutating 关键字.(主要针对value types.当class遵守协议实现方法时,无需在方法前添加mutating)
5.定义initalizer
1.和普通的initalizer定义相同,除了没有{}和方法体
2.可在initializer方法前加required关键字.加了这个关键字后,不但遵守协议的类必须实现这个构造方法,而且它的子类也同样需要实现.(当遵守协议的类是final class,那么它的这个构造方法前面不需加required关键字)
3.可定义 failable initializer .但是遵守协议的子类可以以failable initializer实现 也可以以non-failable initializer实现
定义的non-failable initializer,要求遵守协议的子类必须以non-failable initializer实现 或者 implicitly unwrapped failable initializeer(init!)实现.
6.protocol可以作为类型在很多地方使用.也可以继承其它协议 (和Java中Interface一样)
7.(Extension相关)可以使用Extension让一个已经存在的type遵守一个新的协议
注意:如果此时,这个已经存在的type原来就已经完全实现了协议里的方法,那么Extension只需声明一下不需在里面写实现任何代码(因为已经实现了)
8.可以限制protocol只可以被class遵守. 只需将 class 关键字放在protocol的继承列表中,并且必须是第一个
如:protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {}
9.Protocol Composition (可以实现多协议.注意作为参数和声明变量时的写法)
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(celebrator: protocol<Named, Aged>) {
print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
}
var person: protocol<Named,Aged> = Person(name: "", age: 123);
10. is as? as! 一样适用于Protocol
11.Optional Protocol Requirements
1.使用关键字 optional 并且 protocol 关键字前面必须加 @objc
@objc protocol CounterDataSource {
optional func incrementForCount(count: Int) -> Int
optional var fixedIncrement: Int { get }
}
2.@objc 指示 这个协议应该暴露给OC代码,更多的描述在 Using Swift with Cocoa and Objective-C
3.有@objc属性的协议的必须是classes或从OC继承而来的类.structure和enumeration不能遵守该协议
4.一个可选的协议功能(属性)可以使用optional chaining来调用(引用).
如: someOptionalMethod?(someArgument) 注意:这里的?是在()前面,如果是在()后面,表示的是方法返回的值是optional的而不是方法本身
12.Protocol Extensions
1.可以对Protocol进行extension,添加新的扩展功能(method/property).这样所有遵守该协议的Type都拥有扩展的功能
如 : extension someProtocol {
func randomBool() -> Bool {
return random() > 0.5
}
}
2.可以对Protocol进行extension,在扩展中提供协议里面的method或property的默认实现.
一旦遵守协议的type实现了该method/property,将会覆盖默认实现.
注意,虽然提供了默认实现,也不代表这个功能是optional的.因为调用/引用 这个功能的时候不需要使用optional chaining.
3.给Protocol Extensions 添加约束条件.只有满足该条件的type才能获得对Protocol的扩展功能
extension CollectionType where Generator.Element : TextRepresentable {
func.......
}
注意: 一个遵守了该协议的type满足很多 实现了相同功能的constrained extensions.Swift会选择一个最相符的实现.(??????)