"現(xiàn)在外面整刮著14級臺風(fēng)...我居然還能鎮(zhèn)定的用手機4G網(wǎng)寫完這篇文章"
"無論內(nèi)容如何...別說話,贊我"
---2016.8.2 廣州
類與函數(shù)
在Swift中與類息息相關(guān)的兩個函數(shù)莫過于構(gòu)造函數(shù)和析構(gòu)函數(shù)了,那么似曾相識的構(gòu)造函數(shù)在Swift是怎么樣表現(xiàn)的,析構(gòu)函數(shù)又是怎么一回事呢?
-
類的構(gòu)造函數(shù)
我們知道在Swift中一個類在完成初始化之前必須要給所有的成員屬性賦值,那么我們可以考慮將初始化賦值的代碼寫在init構(gòu)造函數(shù)中,這是因為構(gòu)造函數(shù)的調(diào)用時間點一定在初始化完成之前- init構(gòu)造函數(shù)的基本使用
class Person : NSObject{
var name : String
var age : Int
override init() {
name = ""
age = 0
}
}
- 當(dāng)然,更多的時候我們會在構(gòu)造方法中直接給屬性賦值,如下:
class personItem : NSObject {
var name : String
var height : Double
var age : Int
init(name : String , height : Double , age : Int) {
self.name = name
self.height = height
self.age = age
}
}
- MVC設(shè)計模式中我們常用到字典轉(zhuǎn)模型,在OC中通常會提供一個類工廠來實例化對象,而在Swift中,我們通常會提供一個構(gòu)造方法來快速創(chuàng)建模型,如下:
例:基本的字典轉(zhuǎn)模型方法
class personItem : NSObject {
var name : String
var height : Double
var age : Int
init(dic : [String : NSObject]){
self.name = dic["name"] as! String
self.height = dic["height"] as! Double
self.age = dic["age"] as! Int
}
}
//外界調(diào)用
let dic = ["name" : "lyu" , "height" : 1.80 , "age" : 18]
let item = personItem(dic: dic)
例:使用KVC進行字典轉(zhuǎn)模型
class personItem : NSObject {
var name : String? //注意:使用KVC模式賦值必須先對所有成員變量進行初始化賦值,這是因為KVC并不一定能給所有成員變量都賦值,所以需要我們先手動賦值,并且配合super.init()方法來初始化成員變量
var height : Double = 0.0 //注意:基本類型不能是可選類型,否則KVC轉(zhuǎn)換失敗(結(jié)果為nil)
var age : Int = 0
init(dic : [String : NSObject]){
super.init() //注意,使用KVC為成員變量賦值,必須先進行初始化
setValuesForKeysWithDictionary(dic)
}
//當(dāng)模型的成員變量中沒有外界傳來的字典中的某一個key的時候,程序會崩潰,為了解決這個問題,我們重寫了如下方法,并且放空其實現(xiàn)
override func setValue(value: AnyObject?, forUndefinedKey key: String) {}
}
//外界調(diào)用
let dic = ["name" : "lyu" , "height" : 1.80 , "age" : 18 , "sex" : 1] //注意,模型中并沒有sex這個屬性,然而程序并不會崩潰,這就是我們改寫了上面這個方法的好處
let item = personItem(dic: dic)
-
類的析構(gòu)函數(shù)
Swift通過自動引用計數(shù)(ARC)來對實例進行內(nèi)存管理,當(dāng)一個實例對象的引用計數(shù)為0的時候,系統(tǒng)會自動調(diào)用其析構(gòu)函數(shù)
通常在析構(gòu)函數(shù)中釋放一些資源,如移除通知等操作(類似dealloc)
Tips:
析構(gòu)函數(shù)不可以手動調(diào)用,他會在實例被釋放的時候自動調(diào)用,這點與OC中的dealloc比較相似
- 析構(gòu)函數(shù)的基本格式
格式:
deinit{
//執(zhí)行過程
}
- 析構(gòu)函數(shù)調(diào)用測試
我們知道,蘋果自動引用計數(shù)(ARC)的規(guī)則是,當(dāng)一個對象被強引用一次,引用計數(shù)就會+1,減少一個強直陣引用計數(shù)就會-1,當(dāng)一個實例的引用計數(shù)減少到0的時候,這個實例就會被釋放,基于此原理,我們來簡單做一下deinit的調(diào)用測試
class Person {
var name : String?
deinit
{
print("person -> deinit")
}
}
//外部調(diào)用
var p :Person? = Person()
p = nil //更改指針p的指向,原有的person實例會被釋放,測試打印結(jié)果:person -> deinit
Tips:
nil的內(nèi)存地址是0x0
- 析構(gòu)函數(shù)與Swift中的循環(huán)引用
循環(huán)引用出現(xiàn)的原因很多,我們在這里創(chuàng)建兩個類另他們相互引用,以此做例子來看看Swift中解決這個問題的兩種辦法
//創(chuàng)建兩個類:
class Person {
var dog : Dog?
deinit
{
print("person -> deinit")
}
}
class Dog {
var owner : Person?
deinit
{
print("dog -> deinit")
}
}
//外部調(diào)用:
//實例化兩個對象
var person : Person? = Person()
var dog : Dog? = Dog()
//讓兩個實例相互擁有
person?.dog = dog
dog?.owner = person
//試圖去銷毀兩個實例
person = nil //然而此時并沒有調(diào)用deinit函數(shù),也就意味著兩個實例均沒有被銷毀,于是出現(xiàn)循環(huán)引用問題
dog = nil
- 第一種解決方案:weak
Swift中的weak與OC中的__weak同樣是一個弱引用,那么我們只要讓這兩個類的某一方弱引用另一方就可以輕松的解決這個矛盾,如下
class Person {
weak var dog : Dog? //Person類弱引用Dog屬性,此時外界使用相同的代碼調(diào)用就不會出現(xiàn)循環(huán)引用的問題了
deinit
{
print("person -> deinit")
}
}
- 第二種解決方案:unowned
unowned與OC中的__unsafe_unRetained相同,同樣是一個弱引用
與weak不同的是,當(dāng)unowned修飾的指針指向的對象被銷毀的時候,這個指針并不會指向nil,而是仍然指向原有的那塊存儲空間,從而變?yōu)?strong>野指針
class Person {
unowned var dog : Dog = Dog() //注意,unowned不能修飾可選類型,unowned修飾的指針不可以指向nil,這恰恰與可選類型(可空類型)矛盾
deinit
{
print("person -> deinit")
}
}
Tips:unowned與weak
相同點:都不會給修飾的對象的引用計數(shù)+1
不同點:weak修飾的對象被銷毀,那么這個指針會自動指向nil
unowned修飾的對象被銷毀,這個指針依然會指向原來的內(nèi)存地址,變成野指針,這很容易引起訪問僵尸對象的錯誤