Xcode Playgrounds中的Swift ARC实验
并介绍自动释放池
ARC代表自动引用计数,Swift将其用于动态内存管理。 我正在遍历《 Swift编程语言(Swift 4) 》中的 “自动引用计数”一章,试图在遇到某些矛盾时涵盖所有角度。 至少那是我的第一个想法。
“自动引用计数”一章描述了强大的引用循环,展示了几种可能导致潜在引用的情况,最后,它针对给定情况提出了使用语言构造来避免它们的方法。
在本文中,“ 对象 ”一词用于指代类实例 ,因为“引用计数仅适用于类实例。 结构和枚举是值类型,而不是引用类型,并且不通过引用存储和传递。”
方案1:
对象通过属性相互引用,这两个属性都可以为“ nil`
它建议使用弱引用,以便在删除强引用时,将使用weak
关键字声明的属性设置为nil
。
基类:
类人{
命名:字符串
init(name:String){
打印(“ \(名称)-开始初始化”)
self.name =名称
}
var apartment:公寓?
deinit {print(“ \(name)正在被初始化”)}
}
公寓类{
let单位:字符串
init(单位:字符串){
print(“ \(unit)-开始初始化”)
self.unit =单位
}
弱var租户:人?
deinit {print(“公寓\(单元)正在被初始化”)}
}
创建变量和强引用:
//注意可选的类型声明!
var john:人吗?
var unit4A:公寓?
john = Person(姓名:“ John Appleseed”)
unit4A =公寓(单位:“ 4A”)
查找john
的对象标识符以供以后比较:
让johnID = ObjectIdentifier(john!)。hashValue
//> 105553116545632
打破由john
创建的强引用将导致在Apartment
对象中将tenant
属性设置为nil
:
约翰=零
到目前为止,所有内容ObjectIdentifier
从本书中复制粘贴( ObjectIdentifier
部分除外)。 在这一点上,我想检查tenant
是否真的是nil
但我得到了这个¹:
print(“ \(unit4A!.tenant!.name)”)
//>约翰·Appleseed
ObjectIdentifier(unit4A!.tenant!)。hashValue == johnID
//>是
自动释放池
参加了Stackoverflow并输入了我的问题(“ 弱引用对象属性在强引用对应对象被释放后,是否应该设置为nil? ”),所以有很多主题相同。
弱属性未设置为nil(重复)的答案对我最有帮助:
读取弱变量可能导致指向的对象被保留并自动释放。 然后,对象将至少与当前自动释放池保持活动状态。
大多数问题(包括上面的问题)已作为重复项被关闭,并且引用为什么在强引用消失后我的弱引用却不被清除? 答案甚至还有更多技术性的答案,示例在Objective-C中提供,但他们都提到了动词“ autorelease ”和名词“ autorelease pool ”。
可以在Apple的《 高级内存管理编程指南》中找到有关后者的精妙解释:
自动释放池块提供了一种机制,您可以通过该机制放弃对象的所有权,但可以避免将其立即释放的可能性(例如,从方法返回对象时)。 通常,您不需要创建自己的自动释放池块,但是在某些情况下,您必须这样做或者这样做是有益的。
这是一个Objective-C指南,但是“ 将Swift与Cocoa和Objective-C结合使用(Swift 4)”一书展示了如何在Swift中使用自动释放池块(即使很简短,并且解释本身也从上述指南中完全删除了) 。
以上文章的其余部分(包括代码示例) 摘自 Wei Wang的@AUTORELEASEPOOL文章,该文章解释了自动发布是什么:
Swift在内存管理中使用了自动引用计数(ARC)。 尽管以ARC方式禁止手动调用keep,
release
和autorelease
,但实际上它们实际上是由编译器自动添加的,并在那里被调用。retain
和release
非常简单。 它们将分别增加和减少参考计数。 在这个级别上,autorelease
非常特殊。 接收器将被插入到预先创建的自动释放池中。 当池收到drain
方法时,池中所有对象的引用计数将减少它们出现在池中的时间。
在iOS应用中,主要功能在自动发布池中运行。 该池的
drain
操作将在每个主运行循环结束时进行。 这种延迟释放在开发中是必需的,有时我们希望变量的生存期比其范围长(例如被调用函数),因此我们可以在以后继续使用它。
即使已过时,也值得阅读本文的其余部分。
添加官方(即Apple Developer) autorelease
文档以供参考:
在当前自动释放池块的末尾减少接收者的保留计数。
在方案1中应用autorelease
池
/ *省略基类的声明。 * /
var john:人吗?
var unit4A:公寓?
john = Person(姓名:“ John Appleseed”)
unit4A =公寓(单位:“ 4A”)
约翰!。公寓= unit4A
租户=约翰
约翰=零
//>约翰·Appleseed正在取消初始化
print(“ \(unit4A!.tenant)”)
//>无
删除对Apartment对象的强引用
最后,我从一开始就打算做:将unit4A
设置为nil
,看看会发生什么:
//约翰=零
unit4A =无
//注意,`unit4A`并未被初始化,因为
//`john`仍然对此有很强的参考!
约翰!。公寓!。单位
//>“ 4A”