3

通过书籍首先解释了关于“无效”引用的问题(使用 ARC),如下例所示:

NSDate* date1=[[NSDate alloc]init];
NSDate* date2=date1;
[date1 release];
NSLog(@"%@",date2); // bad access

所以我理解了保留/释放机制:在这种情况下,指令将是:

date2=[date1 retain];

但是当它谈到强/弱引用时,这对我来说听起来很矛盾:

“默认情况下,引用是强引用。如果您将对象分配给强引用,ARC 会假定您希望该对象保留并隐式保留它”

这不是和之前说的矛盾吗?
date2 默认情况下很强大,因此它应该隐式保留 date1 并且不会出现错误的访问异常。
当然我误解了一些东西,有人可以更好地向我解释一下吗?

4

2 回答 2

15

Strong 是默认设置,因为它通常是您想要的,但是使用 ARC,编译器会分析对象的生命周期需要多长时间并在适当的时间释放内存。例如:

- (void)someMethod
{
  NSDate* date = [[NSDate alloc] init]; // date is __strong by default
  NSLog(@"The date: %@", date); // date still contains the object created above

  // Sometime before this point, the object date pointed to is released by the compiler
}

弱引用只保留对象,而它有一个或多个其他强引用。一旦最后一个强引用被破坏,编译器就会释放该对象,并且nil运行时将弱对象引用(变量)更改为。这使得弱变量在局部范围内几乎没有用,就像上面的例子一样。例如:

- (void)someMethod
{
  __weak NSDate* date = [[NSDate alloc] init]; // The date created is released before it's ever assigned to date 
                                               // because date is __weak and the newly created date has no 
                                               // other __strong references
  NSLog(@"The date: %@", date); // This always prints (null) since date is __weak
}

看一个弱变量和强变量在局部范围内一起工作的例子(这只会严重限制有用性,这里实际上只是为了演示弱变量引用):

- (void)someMethod
{
  NSDate* date = [[NSDate alloc] init]; // date stays around because it's __strong
  __weak NSDate* weakDate = date;

  // Here, the dates will be the same, the second pointer (the object) will be the same
  // and will remain retained, and the first pointer (the object reference) will be different
  NSLog(@"Date(%p/%p): %@", &date, date, date);
  NSLog(@"Weak Date(%p/%p): %@", &weakDate, weakDate, weakDate);

  // This breaks the strong link to the created object and the compiler will now
  // free the memory. This will also make the runtime zero-out the weak variable
  date = nil;

  NSLog(@"Date: %@", date); // prints (null) as expected
  NSLog(@"Weak Date: %@", weakDate); // also prints (null) since it was weak and there were no more strong references to the original object
}
于 2012-04-19T22:12:07.813 回答
3

关键错误在于将手动保留释放行为与 ARC 混淆为相同。它不是。在 ARC 下,对象分配既是原子的,又是决定对象生命周期的表达式。

以你的例子并删除retain. 你最终得到这个:

NSDate* date1=[[NSDate alloc]init];
NSDate* date2=date1;
NSLog(@"%@",date2);

在 ARC 下非常有意义;没有手动释放把事情搞砸了。即它会自动工作。

更好的是,因为编译器在幕后进行流控制分析,所以不需要额外的保留或释放。代码实际上是这样的:

NSDate* date1; // date1 initialized to nil -- or not given that it is never read before...
date1 = [[NSDate alloc]init]; // ... this assignment (of a +1 retain count obj)
NSDate* date2=date1; // retain count unchanged
NSLog(@"%@",date2); // retain count unchanged
.... compiler emits equivalent to [date1 release] ...

由于编译器release在最后一次使用date1 or date2之后才会发出它,所以永远不会有悬空指针。

于 2012-04-19T22:09:59.237 回答