ObjectiveC: 使用NSString和__weak与ARC一起时出现奇怪的行为

6

首先是代码和输出结果:

NSString *text = @"Sunny";
__weak NSString *string0 = text.lowercaseString;
__weak NSString *string1;
string1 = text.lowercaseString;

NSLog(@"%@, %@", string0, string1);

输出:

(null), sunny

但是当我将 string1 的声明放在 text 上面时,输出结果就不同了。以下是代码:

__weak NSString *string1;
NSString *text = @"Sunny";
__weak NSString *string0 = text.lowercaseString;
string1 = text.lowercaseString;

NSLog(@"%@, %@", string0, string1);

输出:

sunny, sunny

我对不同的输出非常困惑:

  • 为什么在第一个例子中,string0string1是不同的?
  • 为什么第二个例子的输出与第一个例子不同?

更加奇怪的是,如果您通过保留断点并逐行执行来运行第一个方案,则可以得到正确的输出。但是,如果您删除断点,则会得到 null - Gandalf
1个回答

6
尝试确定对象何时被释放或弱引用何时为空可能很具有挑战性,而且通常并不能真正帮助理解。以下是您可能看到与预期不同结果的一些原因:
- NSString: 在进行这种调查时最好永远不要使用此类型。字符串文字是不可变的,它们不会被收集,并且即使您不希望有一个字符串文字,您也可能拥有一个。
- 自动释放池: 自动释放池实际上是ARC之前的遗留物,但它仍然存在,并且许多方法返回自动释放的对象。这意味着许多对象将比您预期的存活时间长,但不会太长。然而,ARC有技巧可以提前从自动释放池中删除对象,所以您可能首先认为对象将存活更长时间,然后它却没有...
- 弱引用: 经过前两个原因的分析,您应该猜到,如果您可能确实不知道对象何时被释放(如果有),则您可能确实不知道弱引用何时为空。 只需想想“足够快”。
- 优化: 编译器可以进行一些优化,虽然保留程序的正确语义,但可能会改变对象的寿命。
如果您确实想要运行这些调查,则可能会更进一步,如果(a)使用您自己的类类型,而不是任何库中的类型,和(b)使用@autoreleasepool {...}块来限制自动释放对象的寿命。
例如,在我使用的编译器上运行您的代码时,我没有得到(null),但是将第一个赋值更改为string0 = text.lowercaseString.mutableCopy确实会产生一个...找出原因留作练习...
拥有探究精神并进行探索是好的,但要准备好面对非显而易见的事情!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接