0

我只是想知道下面第 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; subtitle 是 MKAnnotation 协议的一部分,具有 nonatomic、readonly 和 copy 属性

问候,西里尔

4

5 回答 5

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 subtitle 属性是只读的,并不意味着您不能用自己的读/写属性覆盖它。例如

@interface MyAnnotation : NSObject <MKAnnotation>

// other stuff

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

@end

如果你再合成它,你会得到所有正确的内存管理代码,你可以这样做

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

或者,如果您必须使用点表示法

self.subtitle = [NSString stringWithFormat: @"test"];
于 2013-05-30T09:25:07.660 回答
1

我认为您的解决方案不是了解字符串初始化的工作原理,而是了解块如何处理变量。

当我想到它时,我认为您可能想通过它的属性而不是 ivar 尝试访问 _subtitle。

self.subtitle

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

于 2013-05-29T14:37:51.583 回答
1

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

_subtitle = @"测试"; //第 1 行

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

如果您仅问上述问题,则两者都是相同的。

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

您正在创建一个新的autoreleased subtitle,一旦块结束,它就会被释放。

于 2013-05-29T14:06:05.890 回答
0

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

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

结果字符串将是(例如,如果您要对其进行 NSLog):“这个数字是 3”

但是你不能这样做:

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

这会给你一个错误。

于 2013-05-29T14:23:58.043 回答
0

如果您查看文档,initWithFormat:它会将您链接到带有许多示例的格式化字符串对象。

这基本上允许 (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"

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

于 2013-05-29T14:08:54.497 回答