Objective c 带弧弱局部变量的生存期

Objective c 带弧弱局部变量的生存期,objective-c,automatic-ref-counting,Objective C,Automatic Ref Counting,如果我有这样一段代码: - (void)testSomething { __weak NSString *str = [[NSString alloc] initWithFormat:@"%@", [NSDate date]]; NSLog(@"%@", str); } - (void)testSomething { __weak NSString *str = [NSString stringWithFormat:@"%@", [NSDate date]]; NSLog(@"

如果我有这样一段代码:

- (void)testSomething
{
  __weak NSString *str = [[NSString alloc] initWithFormat:@"%@", [NSDate date]];
  NSLog(@"%@", str);
}
- (void)testSomething
{
  __weak NSString *str = [NSString stringWithFormat:@"%@", [NSDate date]];
  NSLog(@"%@", str);
}
输出将是(null),因为没有对str的强引用,在我分配它之后,它将立即被释放。这是有道理的,并在“过渡到圆弧”指南中详细说明

如果我的代码如下所示:

- (void)testSomething
{
  __weak NSString *str = [[NSString alloc] initWithFormat:@"%@", [NSDate date]];
  NSLog(@"%@", str);
}
- (void)testSomething
{
  __weak NSString *str = [NSString stringWithFormat:@"%@", [NSDate date]];
  NSLog(@"%@", str);
}
然后它正确地打印出当前日期。显然,您希望它在非ARC世界中工作,因为
str
将自动释放,因此在该方法退出之前有效。然而,在启用ARC的代码中,人们一般认为这两种形式(<代码> StrugFieldFrase
所以我的问题是,像第二个示例这样的代码是否保证在ARC下工作。也就是说,如果我对一个对象的引用弱,我们通常会考虑一个自动还原的方便构造函数,那么在同一个范围内使用这个引用是安全的吗??

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

在此代码中:

__weak NSString *str = [[NSString alloc] initWithFormat:@"%@", [NSDate date]];
 __weak NSString *str = [NSString stringWithFormat:@"%@", [NSDate date]];
对象的唯一保留位置(或等效位置)是alloc。ARC将自动插入释放命令,使其立即释放

同时,在本准则中:

__weak NSString *str = [[NSString alloc] initWithFormat:@"%@", [NSDate date]];
 __weak NSString *str = [NSString stringWithFormat:@"%@", [NSDate date]];
按照惯例,像这样的方便构造函数的返回值必须是自动释放的对象*。这意味着当前的autoreleasepool已保留该对象,并且在该池排空之前不会释放该对象。因此,您几乎可以保证该对象将至少在您的方法期间存在——尽管您可能不应该依赖于这种行为


(*或以其他方式保留)

局部弱变量的生存期根本无法保证。如果变量指向的对象被解除分配,则弱变量随后将指向
nil

如果对通过不返回保留对象的方法获得的对象有弱引用,则可以假定该对象在该方法退出之前一直存在。如果要确保对象存活,请使用强引用

下面的示例表明,不保留方法的返回值不一定会在自动释放池中结束:

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

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

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

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


您可能已经注意到,我切换到不使用库方法,如
+[nsstringwithformat:
。这些似乎总是将对象放在自动释放池中,这可能是出于兼容性原因

这个问题很有趣,但我怀疑最好的答案是“你不应该在意”。你可能是对的。这个问题实际上只是为了确保我理解我所看到的其他一些问题的答案。让编译器担心内存分配<代码>\uuu弱是一种控制实例生存期的无效方法。如果明确希望控制项目的生存期,则使用分配给强引用的
+alloc
表单。然后在退出时取消该引用。无引用是新的
-release
。依我看,
\uuu弱
用于中断保留周期,仅此而已。Andrew P.S.对于ARC,我们都应该“放松下来,想想英格兰。”是的,我同意……我在问这个问题时想到的真正的代码实际上涉及到打破一个保留周期。但是请注意,如果你有
NSString*str=[NSString stringWithFormat:@“%@,[NSDate date]]__弱NSString*weakStr=strstr
在分配给
weakStr
后不再被引用(因此超出范围),则
weakStr
可能最终为零,这取决于
+stringWithFormat:
本身是否在ARC下编译。在ARC中,便利构造函数的返回值不一定会在自动释放池中结束。有关详细信息和示例,请参见我的答案。当然,如果不调用autorelease,对象不会自动结束在autorelease池中。情况从来不是这样。但在实际代码中,如果您有一个方便的构造函数,您希望/需要与现有约定保持一致(即,返回的对象是自动释放的),那么您将对其调用自动释放,因此无论您是否使用ARC,它都将作为自动释放的对象。实际上,对于上面的方法
-anObject
,ARC会自动插入对
objc\u autoreleaseReturnValue
objc\u returnAutoreleaseReturnValue
的调用。如果从非ARC代码调用
-anObject
,则该对象将最终位于自动释放池中,或者甚至在ARC中,除非您将优化级别设置为-Os。由于ARC,惯例是不将该对象添加到自动释放池中,但会尝试对其进行优化,因此无需添加到自动释放池中。添加到自动释放池被描述为“最坏情况”。看见因此,您的第二个示例在ARC下不能得到保证–它现在可能可以工作,但不能得到保证。