stringWithFormat和initWithFormat在ARC中产生不同的值

时间:2016-06-27 09:00:15

标签: ios objective-c nsstring automatic-ref-counting

我是目标C和iOS的新手。当使用NSString stringWithFormat和initWithFormat时,我对2结果值感到困惑:

IBackgroundTask

输出:结果:str0 Hello,str1(null),str2 Hello

环顾网络,这些来电者的答案在ARC示例下是相同的:stringWithFormat vs initWithFormat under ARC

然而,对于上面的代码,str2似乎没有意义,无论弱或强,这里,即我可以删除str2声明的 __ weak 并产生相同的结果。

我担心的是,如果stringWithFormat创建的字符串是由框架所拥有的(或者是用户应用程序范围之外的其他方式)?

4 个答案:

答案 0 :(得分:3)

str1为空,因为您只对字符串有弱引用,因此ARC可能会立即释放它,因为您没有强引用它。事实上,编译器甚至可能会警告你:

  

警告:将保留对象分配给弱变量;对象将在转让后释放。

str2Hello,因为stringWithFormat创建了“自动释放”对象(没有强引用的对象,但是在池耗尽之前,即在您屈服之后,该对象不会被释放回到操作系统)。它不是“由框架所拥有”,而是仅仅尚未被解除分配。

注意,使用NSString查看内存管理有时可能会出现问题(特别是在处理字符串文字时),因为内部优化有时会影响其内存管理,但是这些结果显示我们正是您的'期待。

鉴于非典型的NSString内存管理,您可能希望使用自己的自定义对象来观察此模式:

@interface CustomObject: NSObject
+ (instancetype)customObject;
@end

@implementation CustomObject
+ (instancetype)customObject {
    return [[self alloc] init];
}
@end

__weak CustomObject *obj1 = [[CustomObject alloc] init];
__weak CustomObject *obj2 = [CustomObject customObject];

NSLog(@"obj1=%@; obj2=%@", obj1, obj2);

在这种情况下,您会看到obj1始终为nil,但obj2不是。 basic rule of memory management是您拥有名称以“alloc”,“new”,“copy”或“mutableCopy”开头的任何对象。因此,这些对象的所有权转移给您,ARC将为您释放它们(即您只有一个weak引用,因此它立即被释放)。名称以除这些前缀之外的任何内容开头的对象尚未将所有权传递给您(因此,在Objective-C中,已作为自动释放对象传递给您的应用程序,如果在池耗尽时没有强引用,则将释放该对象。

对于你的问题的根源,对象是否“由框架所有”,答案通常是否定的,但也有例外。例如,NSString有一些优化可以保持字符串引用。同样,有UIImage个方法,特别是imageNamed缓存图像。等

但是,一般来说,你不应该担心操作系统在做什么。只要确保你解决自己的强引用,让操作系统做它将做的事情。通常,如果它进行缓存,则无论如何都会在内存压力下清除这些缓存。

答案 1 :(得分:2)

我对你问题的回答

  

如果你想拥有一个属性应该具有的属性的弱属性   已经保留了它

·H

@property (nonatomic, weak) NSString *str1;
@property (nonatomic, weak) NSString *str2;

的.m

@synthesize str1,str2;


-(void)viewDidLoad
{
   NSString* str0 = @"Hello";
   NSString* str1 = [[NSString alloc] initWithFormat:@"%@", str0 ];
   NSString* str2 = [NSString stringWithFormat:@"%@",str0];
   NSLog(@"Result: str0 %@, str1 %@, str2 %@", str0, str1, str2);
}

输出

Result: str0 Hello, str1 Hello, str2 Hello

Graver answer here

Apple Forum Document

的详细说明
  

区别在于返回值如何由内存管理。   alloc / initWithFormat:返回您必须保留的字符串   自行释放或自动释放。 stringWithFormat:返回一个字符串   已经自动释放。 (一个自动释放的对象将是   当前自动释放池消失时释放;通常   在处理下一个事件之前发生。)

     

您应该使用哪种取决于您对字符串的操作。如果   它是一个临时字符串,如果它将被存储在另一个字符串中   对象,或者如果它将使用。存储在您自己的对象中   “self.property”语法,使用stringWithFormat:;如果它会的话   分配给全局,静态或实例变量(不使用   “self.property”),使用alloc / initWithFormat:。

     

在你的情况下,你可以去任何一种方式。 stringWithFormat:允许   您要删除显式释放调用,但也自动释放   比释放慢一点。由你来决定是否   您希望您的代码更小,更简单,更长或更快。

答案 2 :(得分:0)

弱变量不包含对象的引用。取消分配对象时,弱变量将设置为nil。由于您在其他地方没有引用,这可能随时发生。

另一方面,iOS可以随意保存其他参考资料。因此无法保证弱变量将设置为nil。因此,根据您的代码,每个变量可能为nil,或者可能不是nil,并且值为“Hello”。

这就是你得到的。每个变量都可以设置为nil或包含“Hello”,这就是发生的事情。

答案 3 :(得分:0)

@ gnasher729:我希望知道在哪种情况下,NSString stringWithFormat的弱/强指针使用正确与否,而与NSString alloc,init非常不同。 我认为清楚地理解它有助于确保何时以及如何正确使用。 顺便说一下,我同意@Rob和@ user3182143,NSString stringWithFormat会产生一个自动释放的对象。 为了证明这一点,我做了更改以强制释放该对象,现在它非常清楚:

NSString* str0 = @"Hello";
__weak NSString* str1 = [[NSString alloc] initWithFormat:@"%@", str0 ];

__weak NSString* str2_weak = nil;
NSString* str2 = nil;


@autoreleasepool {
    str2_weak = [NSString stringWithFormat:@"%@",str0];
    str2 = [NSString stringWithFormat:@"%@",str0];
}

NSLog(@"Result: str0 %@, str1 %@, str2_weak %@ str2 %@", str0, str1, str2_weak, str2);

结果:str0 Hello,str1(null),str2_weak(null)str2 Hello

使用上面修改过的代码,一个autoreleasepool块来覆盖stringWithFormat的结果,str2_weak保持对自动释放对象的弱引用,因此它在块之后应为null; str2实际上保持自己的字符串,因此不会被释放。 输出现在对我来说“有意义”: