Swift-ARC(Automatic Reference Counting)

了解java的童鞋都知道GC(垃圾回收),程序员不需要去关心内存动态分配和垃圾回收的问题,交友jvm去处理。在Swift中也有类似的机制,那它是依据什么样的策略来进行垃圾回收(释放空间)的呢?

ARC是如何进行工作的?###


*** 每当你创建一个class的instance,ARC会自动分配空间存储实例信息以及所有与其相关联的属性。一旦当这个实例步不再被使用,ARC就会释放这个实例持有的空间,这样就保证了一些永远不会被用到的实例一直占用内存导致内存out of memory。然而,ARC有时会释放正在使用的实例,这时如果你去方位这个实例的属性或者是方法,你的App可能就会crash掉。为了防止这种情况的发生,ARC会记录每个instance reference的个数,只要还存在一个有效的reference,ARC就不会释放该instance。距离说明如下:***

class Person {
    let name:  String
    init(name: String ) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
} 
class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

每个Person实例都有一个name属性和所居住的apartment,但此时apartment的类型是Optional的,表示可能有的人可能不住apartment或其他一些情况。
每个Apartment都有一个单元号unit,以及居住在其中的房客tenant,tenant也是Optional类型,表示可能改公寓还没有人在住。

创建两个实例,分别是:joh和unit4A,其初始值都为nil

var jhon:Person?
var unit4A:Apartment?

一旦我们开始为它们赋值,比如:

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

那么,jhon相对于Person就有了一个strong reference,同理unit4A对于Apartment也有了一个strong reference。我们以图的形式展示如下:

strongReference.jpeg

这时我们如果将john和unit4A全部赋值为nil,则会调用对应的deinit方法,ARC会回收两个变量的占用空间。但是,如果我们如下面这样去操作:

john!.apartment = unit4A
unit4A!.tenant = john

对应的关系则变为了:


cycleReference.jpeg

此时再将john和unit4A赋值为nil,你会发现对应的deinit方法没有被调用,ARC并没有回收此空间。因为我们上面说过,只有有一个strong reference存在,ARC就不会回收。


cycleReference.jpeg

出现传说中的内存泄漏。
Swift针对此种情况给出了相应的解决方法:两个实例相互持有,且都可以为nil,使用weak关键字避免出现cycleReference,Code如下:

class Person {
    let name:  String
    init(name:  String ) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}
class Apartment {
    let unit: String
    init(unit: String ) { self.unit = unit }
    weak var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var john:  Person
var unit4A:  Apartment
 
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
 
john!.apartment = unit4A
unit4A!.tenant = john

如上重新定义Person和Apartment,并创建实例john和unit4A,对应的关系:

weakReference.jpeg

这是在将jhon赋值为nil,ARC就或自动回收其持空间啦~而此时unit4A!.tenant并不为nil。因为还有一个weak reference存在,但weak reference不会阻止ARC回收其空间,当回收完毕unit4A!.tenant则自动被置为nil,正因为此上面定义Apartment的tenant属性是使用了var而不是let。


****类似的还有unowned,直白的翻译就是不拥有,还是很容易让人理解呀!与weak相比共同点就是都不保持strong hold(官方这么叫,一时间不知道咋翻译啦);不同点是当其他实例有相同或更长的生命周期,任何一个unowned reference都会被当做有值,ARC也不会将其置为nil,如此声明的时候就可以使用let。示例如下:***

class Customer {
    let name:  String
    var card:  CreditCard?
    init(name: String) {
        self.name = name
    }
    deinit { print("\(name) is being deinitialized") }
}
 
class CreditCard {
    let number:  UInt64
    unowned let customer:  Customer
    init(number: UInt64, customer:  Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("Card #\(number) is being deinitialized") }
}

var john:  Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

这时,Customer有了一个strong reference指向CreditCard,同时CreditCard有unowned reference指向Customer:

weakReference.jpeg

而此时将john置为nil,由于unowned customer reference,发现两个deinit方法都会执行。

额外的,对于Closures也有类似的cycle reference需要特别注意,具体的避免方法同上,下面之举一个简单的例子:###

class HTMLElement {
    
    let name:  a href="" String /a 
    let text:  a href="" String /a ?
    
    lazy var asHTML: () ->  a href="" String /a  = {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }
    
    init(name:  a href="" String /a , text:  a href="" String /a ? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        print("\(name) is being deinitialized")
    }
}

var paragraph:  a href="" HTMLElement /a ? = HTMLElement(name: "p", text: "hello, world")

其reference如图所示:

addtional.jpeg

解决方法:

class HTMLElement {
    
    let name:  a href="" String /a 
    let text:  a href="" String /a ?
    
    lazy var asHTML: () ->  a href="" String /a  = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }
    
    init(name:  a href="" String /a , text:  a href="" String /a ? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        print("\(name) is being deinitialized")
    }
    
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容