1. 程式人生 > >Swift中的weak和unowned關鍵字

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

中使用關鍵字weakself進行修飾,避免迴圈引用的產生。

程式碼如下:

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關鍵字。