使用ARC的弱局部变量的生命周期

时间:2012-02-08 22:54:37

标签: objective-c automatic-ref-counting

如果我有一段看起来像这样的代码:

- (void)testSomething
{
  __weak NSString *str = [[NSString alloc] initWithFormat:@"%@", [NSDate date]];
  NSLog(@"%@", str);
}

输出将为(null),因为没有对str的强引用,它将在我分配后立即释放。这是有道理的,并在“过渡到ARC”指南中详细说明。

如果我的代码如下:

- (void)testSomething
{
  __weak NSString *str = [NSString stringWithFormat:@"%@", [NSDate date]];
  NSLog(@"%@", str);
}

然后它正确打印出当前日期。显然你会期望它在非ARC世界中工作,因为str将被自动释放,因此在此方法退出之前有效。但是,在启用ARC的代码中,人们通常认为两种形式(stringWithFormatalloc/initWithFormat)是等效的。

所以我的问题是,第二个例子的代码是否可以保证在ARC下工作。也就是说,如果我对通过我们通常认为是自动释放的便利构造函数的对象的弱引用,是否保证在同一范围内使用该引用是安全的我通常会没有ARC(即直到方法退出)?

2 个答案:

答案 0 :(得分:5)

自动释放和分配的约定仍适用于ARC世界。唯一的区别是ARC将插入额外的保留/释放调用,以使泄漏对象或访问解除分配的对象更加困难。

在此代码中:

__weak NSString *str = [[NSString alloc] initWithFormat:@"%@", [NSDate date]];

保留对象(或等效对象)的唯一位置是alloc。 ARC将自动插入一个释放命令,使其立即被释放。

同时,在此代码中:

 __weak NSString *str = [NSString stringWithFormat:@"%@", [NSDate date]];

按照惯例,像这样的便利构造函数的返回值必须是一个自动释放的对象*。这意味着当前的autoreleasepool已保留该对象,并且在池耗尽之前不会释放它。因此,您几乎可以保证此对象至少在您的方法持续时间内存在 - 尽管您可能不应该依赖此行为。

(*或以其他方式保留)

答案 1 :(得分:1)

根本不保证本地弱变量的生命周期。如果变量指向的对象被释放,则弱变量将在之后指向nil

如果您对通过不返回保留对象的方法获得的对象具有弱引用,则安全地假定此对象存在直到方法退出。如果要确保对象存活,请使用强引用。

这是一个示例,显示非保留方法的返回值不能保证在自动释放池中结束:

  • 创建一个新的iOS项目(使用ARC和Storyboard的单一视图应用程序)
  • 将此方法添加到AppDelegate.m

    + (id)anObject
    {
        return [[NSObject alloc] init];
    }
    
  • 替换-application:didFinishLaunchingWithOptions:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        __weak id x = [AppDelegate anObject];
        NSLog(@"%@", x);
        return YES;
    }
    
  • 重要:现在将调试的优化级别设置为-Os

在此示例中,+[AppDelegate anObject]的作用类似于便利构造函数,但如果您在具有(null)优化的设备上执行-Os,则会看到+[NSString stringWithFormat:]。原因是一个漂亮的ARC优化,可以防止将对象添加到自动释放池的开销。

您可能已经注意到我切换到不使用像{{1}}这样的库方法。这些似乎总是将对象放在自动释放池中,这可能是出于兼容性原因。