【问题标题】:Objective C, what [NSString initWithFormat] exactly does?Objective C,[NSString initWithFormat] 到底是做什么的?
【发布时间】:2013-05-29 13:57:06
【问题描述】:

我只是想知道下面第 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 属性

问候, 西里尔

【问题讨论】:

  • 我认为这个答案适合这个问题:stackoverflow.com/a/4154419/883799
  • 您可以查看这个不错的答案:stackoverflow.com/questions/8275131/…
  • 最后你在一个块中执行这个代码,这可能会导致问题。
  • 这段代码是使用ARC还是手动引用计数?还有,_subtitle的声明是什么?
  • 感谢您的回答。所以 _subtitle 来自 @synthesize subtitle = _subtitle; subtitle 是 MKAnnotation 协议的一部分,具有 nonatomic、readonly 和 copy 属性。而且,我没有使用 ARC。

标签: ios objective-c nsstring mkannotation stringwithformat


【解决方案1】:

如果您不使用 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"];

【讨论】:

    【解决方案2】:

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

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

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

    如果你只问上面这两个都是一样的。

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

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

    【讨论】:

    • ARC应该没有问题
    • 好的,但我没有使用 ARC。所以第 1 行不会创建自动释放?那么为什么我们从不以与第 1 行相同的方式释放对象声明呢?干杯,
    • +1 如果您不使用 ARC,这是正确的答案。我打算写一个长评论来更详细地解释这一点,但我会写一个答案。
    • @JeremyP:当然,伙计。我们将详细了解。
    【解决方案3】:

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

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

    self.subtitle
    

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

    【讨论】:

    • ARC应该没有问题
    • 为什么仅仅因为 ARC 完成了所有的内存管理并不意味着变量不需要增加它的保留计数。访问 ivar 不会发生以下情况?
    • 但是 ARC 应该为你增加保留计数 - 假设变量是 __strong
    • 没错,当您直接访问 ivar 时不会发生这种情况。
    • 是的,它适用于 ARC。我承认如果你在一个块中这样做可能会被破坏
    【解决方案4】:

    如果您查看 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"
    

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

    【讨论】:

    • @"Test" 中没有格式说明符,因此不需要参数。
    【解决方案5】:

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

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

    结果字符串将是(例如,如果您要对其进行 NSLog):“This number is 3”

    但是你不能这样做:

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

    这会给您带来错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-06
      • 2015-08-18
      • 2015-08-06
      • 2013-09-02
      • 2014-01-02
      • 2013-10-10
      • 2017-05-08
      • 2022-01-20
      相关资源
      最近更新 更多