循環(huán)強引用

循環(huán)強引用會導致內(nèi)存泄漏
內(nèi)存泄漏(Memory Leak)是指程序中己動態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放弟塞,造成系統(tǒng)內(nèi)存的浪費,導致程序運行速度減慢甚至系統(tǒng)崩潰等嚴重后果
swift給出兩種解除循環(huán)引用的方式捐迫,弱引用weak 和無主引用unowned

一酵紫、類之間互相持有會引發(fā)強引用
class Teacher{
    var student:Student?
    deinit {
        print("Teacher被銷毀了")
    }
}

class Student{
    var teacher:Teacher?
    deinit {
        print("Student被銷毀了")
    }
}
var tea:Teacher?
var stu:Student?
tea = Teacher()
stu = Student()
tea?.student = stu
stu?.teacher = tea
tea = nil
stu = nil

如上所示亡鼠,tea、stu置為nil之后稳强,控制臺也沒有輸出任何信息场仲,證明兩個對象都沒有被銷毀,造成了內(nèi)存泄漏键袱。
解決辦法如下:在任一類里邊引用屬性前添加weak即可

class Teacher{
    var student:Student?
    deinit {
        print("Teacher被銷毀了")
    }
}

class Student{
    weak var teacher:Teacher?
    deinit {
        print("Student被銷毀了")
    }
}
var tea:Teacher?
var stu:Student?
tea = Teacher()
stu = Student()
tea?.student = stu
stu?.teacher = tea
tea = nil
stu = nil

控制臺:

Teacher被銷毀了
Student被銷毀了

其實上邊提到的解決循環(huán)引用的方法燎窘,可以使用弱引用weak,也可以使用無主引用unwoned蹄咖。
unowned與weak的區(qū)別是褐健,無主引用無法在實例被銷毀后被設置為nil,這時候被訪問就會觸發(fā)運行時錯誤澜汤。
倘若你使用 weak,屬性可以是可選類型蚜迅,即允許有 nil 值的情況。另一方面俊抵,倘若你使用 unowned谁不,它不允許設為可選類型。因為一個 unowned 屬性不能為可選類型徽诲,
根據(jù)屬性是否為可選類型刹帕,你可以在 weak 和 unowned 之間進行選擇吵血。

tips:

  • 當兩個實例屬性都允許為nil時,適合弱引用偷溺;
  • 當兩個實例屬性一個允許為nil蹋辅,另一個不允許為nil時,適合無主引用挫掏;
  • 當兩個實例屬性都不允許為nil時侦另,這時候為了解決兩個實例之間的循環(huán)引用,就需要一個類使用無主引用尉共,另一個類使用隱式解析可選屬性褒傅,具體如下:
    首先需要明確一點,可選類型使用的時候需要解包袄友,隱式可選類型使用的時候不需要解包殿托,詳見Optional可選類型
class City{
    let name:String
    var province:Province!
    init(cityName:String, provinceName:String){
        self.name = cityName
        self.province = Province(name:provinceName, city:self)
    }
    deinit {
        print("City Destoryed")
    }
}

class Province{
    let name:String
    unowned var city:City
    init(name: String, city:City){
        self.name = name
        self.city = city
    }
    deinit {
        print("Province Destoryed")
    }
}

var city:City? = City(cityName:"石家莊" ,provinceName:"河北")
print(city!.province.name)
city = nil

控制臺:

河北
City Destoryed
Province Destoryed
本人的疑問:

1、為什么要聲明為隱式可選類型杠河?
排除法:

  • 聲明為非可選類型var province:Province 碌尔?
    系統(tǒng)會報錯浇辜,詳細信息見圖片券敌,是因為self的存儲屬性還沒有初始化完成,你就使用self當做參數(shù)柳洋,所以報錯待诅。
    所以需要聲明為隱式可選類型,這樣意味著province有默認值nil熊镣。調(diào)用self當做參數(shù)就不會報錯卑雁。
Snip20170628_2.png
  • 聲明為可選類型?
    如下圖绪囱,既然已經(jīng)確定province有值测蹲,再聲明成可選類型的話就會造成代碼冗余,最明顯的就是空合運算符那里鬼吵,根本就不會走到扣甲。


    Snip20170628_5.png
二、閉包可能引起循環(huán)強引用

造成強引用的原因是閉包賦值給類的屬性齿椅,同時閉包內(nèi)部引用了這個類的實例琉挖,跟OC里邊的block循環(huán)引用是一樣一樣的。
看下邊例子:

class Student{
    var name:String
    var score:Int
    //這里使用lazy是因為下邊用到了self.score 不使用lazy會提示我們self還沒有初始化.
    //使用了懶加載就不一樣了,等用到level的時候self肯定已經(jīng)初始化了涣脚,就不會報錯了示辈。
    lazy var level :() -> String= {
        in
        switch self.score{
        case 0..<60:
            return "D"
        default:
            return "E"
        }
    }
    init (name:String, score:Int){
        self.name = name
        self.score = score
    }
    deinit {
        print("Student destoryed")
    }
}
var stu:Student?
stu = Student(name:"張三", score:45)
print(stu!.level())
stu = nil

控制臺: 并沒有輸出銷毀信息,證明循環(huán)引用了遣蚀。

D
如何解決循環(huán)引用呢矾麻?

解決方法有三種

  • [weak self]
  • [unowned self]
  • weak var weakSelf = self 然后使用weakSelf
class Student{
    var name:String
    var score:Int
    //這里使用lazy是因為下邊用到了self.score 不使用lazy會提示我們self還沒有初始化.
    //使用了懶加載就不一樣了,等用到level的時候self肯定已經(jīng)初始化了纱耻,就不會報錯了。
    lazy var level:() -> String = {
        //方式一:
        //[weak self] in
        //switch self!.score{
        
        //方式二:
        //[unowned self] in
        //switch self.score{
        
        //方式三:
        weak var weakSelf = self
        switch weakSelf!.score{
        case 0..<60:
            return "D"
        default:
            return "E"
        }
    }
    init (name:String, score:Int){
        self.name = name
        self.score = score
    }
    deinit {
        print("Student destoryed")
    }
}
var stu:Student?
stu = Student(name:"張三", score:45)
print(stu!.level())
stu = nil

控制臺:

D
Student destoryed

證明Student對象銷毀了险耀,解決循環(huán)引用成功
這里詳細解釋下方式三
其實方式三是可以用的膝迎,只不過我這里的例子有點尷尬。
weak var weakSelf = self 這句代碼是一定要放到閉包外邊的胰耗,因為就是為了防止引用self限次。你放到里邊之后還不是引用了。
我這里是因為在初始化完成之前不能使用self柴灯,會報錯卖漫。所以方式三的道理是沒錯的。
有不懂的可以隨時私信我赠群。我會解答

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末羊始,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子查描,更是在濱河造成了極大的恐慌突委,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冬三,死亡現(xiàn)場離奇詭異匀油,居然都是意外死亡,警方通過查閱死者的電腦和手機勾笆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門敌蚜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窝爪,你說我怎么就攤上這事弛车。” “怎么了蒲每?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵纷跛,是天一觀的道長。 經(jīng)常有香客問我邀杏,道長贫奠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任淮阐,我火速辦了婚禮叮阅,結果婚禮上,老公的妹妹穿的比我還像新娘泣特。我一直安慰自己浩姥,他們只是感情好,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布状您。 她就那樣靜靜地躺著勒叠,像睡著了一般兜挨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上眯分,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天拌汇,我揣著相機與錄音,去河邊找鬼弊决。 笑死噪舀,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的飘诗。 我是一名探鬼主播与倡,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼昆稿!你這毒婦竟也來了纺座?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤溉潭,失蹤者是張志新(化名)和其女友劉穎净响,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喳瓣,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡馋贤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了夫椭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掸掸。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡氯庆,死狀恐怖蹭秋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情堤撵,我是刑警寧澤仁讨,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站实昨,受9級特大地震影響洞豁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荒给,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一丈挟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧志电,春花似錦曙咽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孝情。三九已至,卻和暖如春洒嗤,著一層夾襖步出監(jiān)牢的瞬間箫荡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工渔隶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留羔挡,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓间唉,卻偏偏與公主長得像婉弹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子终吼,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容