2016-07-14 38 views
-1

我学习obj-c/swift弧系统。通过CFGetRetainCount函数打印创建实例的保留计数的日志。为什么Obj-C实例有1个保留计数刚刚创建?

我希望像这样的

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个保留计数和释放实例。这些现象的原因是什么?

+2

因为'foo1','foo2'是常量,所以你的代码甚至不能编译*。即使你将它们声明为变量,你也不能给它们分配'nil'。你真的测试了什么? –

+0

我从来不认为CFGetRetainCount可以告诉我关于对象保留数量的信息。尝试简单的代码:var foo1:NSNumber? = NSNumber(value:0) print(CFGetRetainCount(foo1))。它的打印量非常大 – larva

+1

您正在询问关于代码的问题。发布您所询问的代码并不是您现场制作的代码,这是很平常的礼貌。 – gnasher729

回答

2

我学习OBJ-C/SWIFT弧系统。

如果您试图了解ARC和保留计数如何在较高级别上工作,那么您的方向会错误。见hereherehere

什么是这些现象的原因是什么?

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

如果你真的想更深的潜水这里在斯威夫特一个paper on ARC

2

TL; DR要登录可能会影响结果的方式,你可能会得到登录时临时所有权,因此由1

以下的答案必须增加你所有的打印效果,是因为你的简化不应该在retainCount中真正担心实际价值。

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

请注意,retainCount永远不会达到零。如果所有者的数量为1,并且您失去了所有者,则对象被释放,则计数不会减少。在斯威夫特

@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 

,并用它来代替你的NSObject

为了更好的测试中,我创建了一个OBJ-C级,不ARC编译

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中也有提及。

0

总之:它至少是1,因为当保留计数变为0时,对象消失(因此没有对象询问其保留计数是多少)。

较长的答案可能是这个视频我做了一个朋友很久以前的事:https://www.youtube.com/watch?v=cBN--I31Xjo

不过说真的,如果你使用ARC,你不应该看的保留计数。 ARC会根据需要插入保留,并且ARC在此时保留对象5次是完全正确的,只要它稍后再释放它5次。

这与-retainCountCFGetRetainCount()问题:由于保留数的整点是共享的所有权,你不应该关心还有谁拥有一个参考,你应该只关心你的代码有多少引用认为,它正确地给他们通过确保它没有循环强有力的参考。

相关问题