Swift中的weak和unowned關鍵字
Swift中沒有了strong
, assign
, copy
關鍵字,對於所有的class
型別變數都預設採用了strong
型別,如果需要指定使用weak
,則需要新增weak
關鍵字修飾。
正是由於這種預設的strong
型別,在閉包中會引起迴圈引用,導致記憶體無法釋放,為了能夠在閉包(block
)中正常釋放記憶體,需要對閉包中的self
使用弱引用,也就是不持有self
物件。
如下面的程式碼中:
class UserInfoViewController {
// ...
private lazy var updateInfoBlock: (Bool)->Void = {
return { succ in
if succ {
self.updateSuccess()
} else {
self.updateFailed()
}
}
}()
// ...
}
按照上面的程式碼寫的話,就會引入迴圈引用。因為self
(也就是UserInfoViewController
的例項物件)持有updateInfoBlock
,而updateInfoBlock
又反過來持有物件self
,這將會導致兩者的記憶體都無法釋放。
這個時候,我們可以在updateInfoBlock
weak
對self
進行修飾,避免迴圈引用的產生。程式碼如下:
class UserInfoViewController {
// ...
private lazy var updateInfoBlock: (Bool)->Void = {
return { [weak self] (succ) in
if succ {
self?.updateSuccess()
} else {
self?.updateFailed()
}
}
}()
// ...
}
這樣,我們就可以避免迴圈引用了。但是我們注意到,在閉包內,self
變成了optional
型別,這是因為weak
修飾的物件在外界有可能釋放,釋放後就變成了nil
,所以這裡要用optional
。
針對這個例子,我們知道,在updateInfoBlock
的有效期內,self
是不可能釋放的,因為self
釋放需要先釋放updateInfoBlock
,在這種情況下,我們可以使用unowned
代替weak
關鍵字,這樣的話,閉包內的self
物件仍舊是原來的型別,可以直接使用。
程式碼如下:
class UserInfoViewController {
// ...
private lazy var updateInfoBlock: (Bool)->Void = {
return { [unowned self] (succ) in
if succ {
self.updateSuccess()
} else {
self.updateFailed()
}
}
}()
// ...
}
只有當weak
修飾的物件(self
)本身對當前物件(updateInfoBlock
)有強引用,也就是持有當前物件時,才可以把weak
替換為unowned
,因為unowned
修飾的物件在釋放後將會變成野指標,導致應用crash
。所以只有能夠確保修飾的物件(self
)不會先於當前物件(updateInfoBlock
)釋放時,才可以使用unowned
關鍵字。