2

我认为我对 ARC 以及选择合适的生命周期限定符(__strong、、、和)的正确用例有很好的理解。然而,在我的测试中,我发现了一个对我来说没有意义的例子。__weak__unsafe_unretained__autoreleasing

据我了解,两者__weak都不__unsafe_unretained添加保留计数。因此,如果没有其他__strong指向该对象的指针,它会立即被释放(不可变字符串是该规则的一个例外)。在这个过程中唯一的区别是__weak指针被设置为 nil,并且__unsafe_unretained指针被单独留下。

如果我创建一个__weak指向简单的自定义对象(由一个 NSString 属性组成)的指针,我会在尝试访问属性时看到预期的(空)值:

Test * __weak myTest = [[Test alloc] init];
myTest.myVal = @"Hi!";
NSLog(@"Value: %@", myTest.myVal); // Prints Value: (null)

__unsafe_unretained同样,由于产生的悬空指针,我预计生命周期限定符会导致崩溃。然而,事实并非如此。在下一个测试中,我看到了实际值:

Test * __unsafe_unretained myTest = [[Test alloc] init];
myTest.myVal = @"Hi!";
NSLog(@"Value: %@", myTest.myVal); // Prints Value: Hi!

为什么__unsafe_unretained对象没有被释放?

[编辑]:对象正在被释放......如果我尝试用应用程序崩溃替换第 2-3 行(并且在第一行之后立即调用NSLog(@"%@", myTest);覆盖dealloc的 in )。Test我知道不可变字符串将继续可用,即使使用__unsafe_unretained,并且直接指向 NSString 的指针也可以工作。我很惊讶我可以在一个已释放对象上设置一个属性(第 2 行),并且以后可以从指向它所属的已释放对象的指针中取消引用它(第 3 行)!如果有人能解释这一点,它肯定会回答我的问题。

4

5 回答 5

2

我很惊讶我可以在一个已释放对象上设置一个属性(第 2 行),并且以后可以从指向它所属的已释放对象的指针中取消引用它(第 3 行)!如果有人能解释这一点,它肯定会回答我的问题。

当对象被释放时,它不会归零。由于您有一个指向已解除分配对象的指针,并且属性值存储在该指针的某个偏移量处,因此在解除分配后存储和检索该属性值可能会成功,也很可能一切都会因某种原因而崩溃或其他。

您的代码工作非常脆弱,尝试使用“调试时显示反汇编”进行调试并逐步执行,您可能会遇到访问冲突,或者关闭 Xcode 本身...

在 C、Objective-C、C++ 或任何家族中发生奇怪的事情,你永远不应该感到惊讶;相反,为这么少的奇怪事情发生而保留你的惊喜!

于 2012-11-21T00:21:44.547 回答
2

因为 objc 中的常量字符串是一个指向堆地址的常量指针,而且该地址仍然有效。

评论后编辑:

也许是因为测试对象地址的内存没有被覆盖并且仍然包含该对象?猜测……

于 2012-11-20T16:57:36.467 回答
1

You can see when Test is deallocated by implementing its -dealloc method and adding some simple logging.

However, even if Test is deallocated immediately, the memory it occupied in RAM may remain unchanged at the time you call myVal.

于 2012-11-20T17:11:54.147 回答
1

@"hi!"生成一个静态全局常量字符串实例,实际上是一个单例。因此,它永远不会被释放,因为它一开始并没有真正分配(至少,它真的不是一个正常的堆分配)。

任何时候你想探索对象的生命周期问题,总是使用 NSObject 的子类来保证行为,并通过覆盖行为轻松地放入日志钩子。

于 2012-11-20T17:23:22.257 回答
0

没什么奇怪的……你需要至少 1 个对对象的强引用才能让它保持活力。

Test * anTest = [[Test alloc] init];
Test * __weak myTest = anTest;
myTest.myVal = @"Hi!";
NSLog(@"Value: %@", myTest.myVal); // Prints Value: (Hi)
于 2013-05-28T13:39:50.187 回答