为什么Obj-C实例有1个保留计数刚创建?

时间:2016-07-14 06:46:27

标签: ios objective-c swift automatic-ref-counting

我研究了obj-c / swift arc系统。 print log on保留CFGetRetainCount func创建的实例的计数。

我希望参考计数像这些

let foo1 = NSObject()  // foo1 retain count 1
let foo2 = foo1        // foo1 retain count 2
foo2 = nil             // foo1 retains count 1
foo1 = nil             // foo1 retain count 0. release

但实际上......

let foo1 = NSObject()  // foo1 retain count 2
let foo2 = foo1        // foo1 retain count 3
foo2 = nil             // foo1 retain count 2
foo1 = nil             // foo1 retain count 1. release

并直接打印NSObject()的保留计数..

print(CFGetRetainCount(NSObject()))  // retain count 1

基本上,NSObject()有1个保留计数。并在保留计数达到2时释放对象。

我知道在强烈关联实例时增加保留计数。但是当保留计数变为1而不是0时,刚刚创建的实例有1个保留计数和释放实例。这些现象的原因是什么?

4 个答案:

答案 0 :(得分:2)

  

我研究了obj-c / swift arc系统。

如果您试图了解ARC如何在高水平上保持计数,那么您的方向是错误的。请参阅herehere以及here

  

这些现象的原因是什么?

在编译器中,ARC是一个非常复杂的系统,是许多优化层的基础。很难理解实际的保留计数值。此外,它受优化级别的影响。

如果你真的想深入了解这里是一个paper on ARC在Swift。

答案 1 :(得分:2)

TL; DR 您记录的方式会影响结果,您可能会在记录时获得临时所有权,因此将所有打印结果提高1。

以下答案是一种简化,因为您不应该真正担心retainCount中的实际价值。

保留计数会计算给定对象有多少引用(所有者)。 创建时,只有一个所有者,因此保留计数设置为1.每次对象获得新所有者(retain)时,保留计数增加1。每当对象丢失并且所有者(release)时,保留计数减少一个。

请注意,retainCount永远不会达到零。如果所有者的数量为1并且您失去了所有者,则该对象将被取消分配,则计数不会减少。

为了更好的测试,我创建了一个没有ARC编译的Obj-C类:

@implementation TestObject

- (instancetype)init {
    TestObject *result = [super init];

    NSLog(@"Retain count after creation: %@", @(self.retainCount));

    return result;
}

- (instancetype)retain {
    TestObject *result = [super retain];
    NSLog(@"Retain count after retain: %@", @(self.retainCount));

    return result;
}

- (oneway void)release {
    NSLog(@"Retain count before release: %@", @(self.retainCount));

    [super release];
}

- (void)dealloc {
    NSLog(@"Retain count before dealloc: %@", @(self.retainCount));
    [super dealloc];
}

@end

并在Swift中使用它而不是NSObject

var foo1: TestObject? = TestObject()
print("#")
print(CFGetRetainCount(foo1))
var foo2 = foo1
print("#")
print(CFGetRetainCount(foo1))
foo2 = nil
print("#")
print(CFGetRetainCount(foo1))
foo1 = nil

导致:

Retain count after creation: 1
#
Retain count after retain: 2
2
Retain count before release: 2
Retain count after retain: 2
#
Retain count after retain: 3
3
Retain count before release: 3
Retain count before release: 2
#
Retain count after retain: 2
2
Retain count before release: 2
Retain count before release: 1
Retain count before dealloc: 1

这基本上是您所期望的,但是当您将对象传递给函数时获得临时所有权时,每个CFGetRetainCount附近都会有额外的保留和释放。

这是为什么你永远不应该读取retainCount的值的一个例子。它没有调试值,documentation中也提到了这一点。

答案 2 :(得分:0)

简而言之: 至少为1,因为当保留计数变为0时,对象消失(所以没有对象可以询问它的保留计数是什么)。

更长的答案可能是我为很久以前的朋友拍摄的这段视频:https://www.youtube.com/watch?v=cBN--I31Xjo

但实际上,如果您使用ARC,则不应该查看保留计数。 ARC将根据需要插入保留,并且ARC完全可以在此时保留对象5次,只要它稍后再释放它5次。

这是-retainCountCFGetRetainCount()的问题:由于保留计数的整个点是共享所有权,你不应该关心谁拥有一个引用,你应该只关心你的代码有多少引用保持并通过确保它没有循环强引用来正确地放弃它们。

答案 3 :(得分:0)

我认为发生这种情况是因为当您将对象传递给CFGetRetainCount函数或任何函数时,保留计数应增加一。