目标C,[NSString initWithFormat]究竟做什么?

时间:2013-05-29 13:57:07

标签: ios objective-c nsstring mkannotation stringwithformat

我想知道下面第1行和第2行之间的区别:

_subtitle = @"Test"; //Line 1
_subtitle = [NSString stringWithFormat: @"Test"]; //Line 2

如果我问这个问题,那是因为我使用MKAnnotation遇到了问题。在下面的方法中,我尝试更新MKAnnotation的字幕委托属性(非原子,复制和只读)。但是看起来我在使用第2行时得到了一个僵尸而在使用第1行时没有任何东西。所以我的问题是为什么?

- (void) initCoordinateWithAddress:(NSString*)address;
{
self.address = address;

CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString: address completionHandler:^(NSArray *placemarks,NSError *error)
{
    CLPlacemark *place = [placemarks objectAtIndex:0];
    _coordinate = place.location.coordinate;
    _title = self.address;
    _subtitle = @"Test"; //Line 1: don't crash
     _subtitle = [NSString stringWithFormat: @"Test"]; //Line 2: crash
    //_subtitle = [[NSString stringWithFormat: @"[%.2f,%.2f]", self.coordinate.latitude, self.coordinate.longitude] copy];
    _isInit = YES;

    [self.customDelegate didCalculateCoordinate: place.location.coordinate forAnnotation: self];
}];

}

我实际上已经通过使用方法副本修复了我的问题,但我仍然不明白第1行和第2行之间有什么区别,如果有人能帮我理解差异是什么,我将不胜感激。

编辑:

1-我没有使用ARC

2- _subtitle来自@synthesize subtitle = _subtitle;字幕是MKAnnotation协议的一部分,属性非原子,只读和复制

此致 西里尔

5 个答案:

答案 0 :(得分:2)

如果您不使用ARC,答案很简单,就是Anoop Vaida写的。但是,我认为需要进一步解释。

这一行

_subtitle = @"Test";

创建对字符串文字的引用。如果你在当前的基础实现中保留其保留计数的峰值,你会发现它是一个非常大的数字(我认为NSIntegerMax)。如果-release-retain的代码遇到保留计数的此值,则它们不会递减或递增。因此,字符串文字具有无限的生命周期。

这一行:

_subtitle = [NSString stringWithFormat: @"Test"];

创建一个您不拥有的字符串。除非您采取措施声明所有权,否则它可能随时消失,最有可能在自动释放池耗尽时消失。您的选项是创建一个您拥有的字符串

_subtitle = [[NSString alloc] initWithFormat: @"Test"];

或保留它。

_subtitle = [NSString stringWithFormat: @"Test"];
[_subtitle retain]; // Can be combined with the previous line if you like.

或复制

_subtitle = [[NSString stringWithFormat: @"Test"] copy];

请注意,在所有情况下,您需要在覆盖它之前释放_subtitle的先前值,否则您将收到泄漏,例如

[_subtitle release];
_subtitle = [[NSString alloc] initWithFormat: @"Test"];

这就是拥有房产更好的原因。仅仅因为MKAnnotation字幕属性是只读的,并不意味着你不能用你自己的读/写属性覆盖它。 e.g。

@interface MyAnnotation : NSObject <MKAnnotation>

// other stuff

@property (readwrite, copy, nonatomic) NSString* subtitle; 

@end

如果你然后合成它,你将获得所有正确的内存管理代码,你可以做到

[self setSubtitle: [NSString stringWithFormat: @"test"]];

或者,如果必须使用点符号

self.subtitle = [NSString stringWithFormat: @"test"];

答案 1 :(得分:1)

  

我只是想知道第1行和第2行之间的区别   波纹管:

     

_subtitle = @“测试”; //第1行

     

_subtitle = [NSString stringWithFormat:@“Test”]; //第2行

如果你问上面这两个是相同的。

在检查代码时,差异非常明显。

您正在创建一个新的autorelease d subtitle,一旦该区块结束就会被释放。

答案 2 :(得分:0)

如果您查找initWithFormat:的文档,则会将您链接到Formatting String Objects,其中包含许多示例。

这基本上允许(s)printf样式的格式字符串,如下所示:

NSString *string1 = [[NSString alloc] initWithFormat:@"A string: %@, a float: %1.2f",
                                                     @"string", 31415.9265];

// string1 is "A string: string, a float: 31415.93"

关键是通过在字符串参数之后添加,来指定参数。

答案 3 :(得分:0)

'[NSString stringWithFormat:]'允许您在字符串中添加变量,例如:

int myVar = 3;
NSString *myString = [NSString stringWithFormat:@"This number is %i", myVar];

结果字符串将是(例如,如果你是NSLog它):“这个数字是3”

但你不能这样做:

NSString *myString = @"This number is %i", myVar;

哪会出现错误。

答案 4 :(得分:0)

我认为你的解决方案不是要理解字符串初始化是如何工作的,而是更多地讨论块如何处理变量。

当我考虑它时,我想你可能想尝试通过它的属性访问_subtitle而不是它的ivar。

self.subtitle

这应该增加保留计数并保持一切正常。