【问题标题】:When not to alloc and init an NSString何时不分配和初始化 NSString
【发布时间】:2010-09-27 04:40:37
【问题描述】:

每当我需要创建一个新的 NSString 变量时,我总是分配并初始化它。似乎有时您不想这样做。你怎么知道什么时候分配和初始化一个 NSString 什么时候不?

【问题讨论】:

  • 你的问题没什么意义。给我们看一些例子。
  • 通过[[NSString alloc] init]; 创建一个新的NSString 是您在Cocoa 中可以做的最没有意义的事情之一。结果字符串是不可变的且为空的。

标签: objective-c cocoa memory-management nsstring string


【解决方案1】:

每当我需要创建一个新的 NSString 变量时,我总是分配并初始化它。

不,这没有意义。

变量从程序遇到你声明它的那一刻起就存在:

NSString *myString;

此变量不是 NSString。它是指向 NSString 的指针的存储。这就是* 所表明的:这个变量持有一个指针。

NSString object 仅在您创建对象的那一刻就存在:

[[NSString alloc] init];

并且指向该对象的指针仅在您将其分配在那里的那一刻起就在变量中:

myString = [[NSString alloc] init];
//Or, initializing the variable in its declaration:
NSString *myString = [[NSString alloc] init];

因此,如果您要从其他地方获取字符串对象(例如,substringWithRange:),您可以跳过创建一个新的空对象,因为您只是要替换指向空字符串的指针用指向另一个的指针。

有时你确实想创建一个空字符串;例如,如果您要一次获取一堆字符串(例如,从 NSScanner)并希望将其中的部分或全部连接成一个大字符串,您可以创建一个空的可变字符串(使用 @987654328 @ 和 init) 并发送 appendString: 消息以进行连接。

您还需要releasealloc 创建的任何对象。这是Memory Management Programming Guide 中的规则之一。

【讨论】:

  • 提醒:在ARC下构建应用时,忽略release部分。此外,如果您想自记录实例化一个空字符串(与此答案中描述的 nil 指针相反),请使用此便捷类方法:NSString* myString = [NSString string];
  • @BasilBourque:更惯用的是@"",尽管不能保证它是一个新字符串(尽管[[NSString alloc] init] 也不是,它可能会返回一个常量字符串)。
  • [NSString string] 对我来说似乎更具自我记录性,因为这绝对意味着“我想要一个非零空字符串”。 @"" 有一些歧义——作者只是忘记填写预期的字符串文字了吗? (我已经看到当犹豫不决悬停在确切措辞的选择上时会发生这种情况。)另一方面,如果您将来确实可能将其更改为非空文本,请使用@"" in第一名。
  • 所以你使用 alloc init 'if' 你不想说 mystring = youstring 即你想给一个新的值像 @"Thanks_Peter" 或者如果你想给它附加一些东西,但是由于您不能附加到尚未创建的内容,因此您将创建一个空的?--对吗?
  • @Honey:我不确定你所说的前者是什么意思。后者只对 NSMutableString 是正确的:你不能追加到[[NSString alloc] init]
【解决方案2】:

如果你想将它初始化为一个已知值,使用alloc没有什么意义,你可以使用字符串文字:

NSString* myStr = @"Some value";

如果您想使用某种格式或其他方式对其进行初始化,但又不需要它停留在当前自动释放池的生命周期之外,那么使用类便利方法会更简洁一些:

NSString* myTempStr = [NSString stringWithFormat:@"%d", myIntVar];

如果您需要它的生命周期超出此范围,请alloc/init 或在之前的调用中添加retain。我倾向于稍微喜欢后者,但两者几乎是等价的。无论哪种方式,您稍后都需要平衡release

请注意,由于NSString 是不可变的,这种事情不仅是不必要的,而且是积极错误

// don't do this!
NSString* myStr = [[NSString alloc] initWithString:@""];
myStr = someOtherStr;

因为它泄露了初始占位符值。

【讨论】:

  • 你怎么知道当前自动释放池的生命周期是多少?
  • @awakeFromNib 通过阅读内存管理文档的relevant section。通常你可以认为一个自动释放的对象是持久的,直到你让它离开你的视线,然后再长一点(即,长到足以成为一个有效的返回值)。如果您在循环中创建内容,您可能希望管理自己的自动释放池以避免建立大量未释放的分配,但在事件处理期间,对于少数字符串来说,默认值应该没问题。
  • 这很挑剔,但 @"" 占位符值不会泄露:它占用了应用程序二进制文件中的空间,因此没有什么可以释放的。这有点浪费,但你实际上并没有泄漏内存......
  • @KevinFrei 占位符是指明确分配给myStralloc-ed 对象,而不是传递给initWithString: 的静态@""。分配someOtherStr 时指针丢失,因此- 至少概念上 - 它泄漏了。 initWithString: 可能会在内部释放分配的字符串并返回指向常量 @"" 的指针,但这没有记录在案,必须被视为实现细节。如果我使用initWithFormat: 代替initWithString: 或其他什么,请考虑这种情况。
【解决方案3】:

似乎有时您不想这样做。

我想不出任何时候我想要分配/初始化一个 NSString。由于 NSStringgs 是不可变的,您几乎总是通过以下之一创建新字符串:

  • 方便类方法例如

    NSString* foo = [NSString stringWithFormat:...];
    
  • 字面意思

    NSString* foo = @"literal";
    
  • NSString 实例方法

    NSString* foo = [bar uppercaseString];
    
  • 从可变字符串复制

    NSString* foo = [mutableBar copy];  // foo needs to be released or autoreleased in this case
    

【讨论】:

  • 您可能想要读取一个文件并将其存储在一个实例变量中,在这种情况下您将使用initWithContentsOfFile:encoding:error:。 (或stringWith…retain,但这对您或程序来说都没有效率。)
  • @Peter Hosey:在这种情况下,我会使用便捷类方法。
【解决方案4】:

我猜你指的是使用 StringWithString 或类似的东西而不是 initWithString? StringWithString 为你分配和初始化,然后返回一个自动释放的字符串。

如果你不需要对字符串进行任何操作,除了拥有字符串,你可以使用NSString *str = @"string";

一般来说,在 iOS 中,您对内存的管理越严密越好。这意味着如果你不需要从一个方法中返回一个字符串,你应该分配 init 然后释放它。

如果你需要返回一个字符串,当然你需要返回一个自动释放的字符串。我不认为它比这更复杂。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
  • 2011-07-05
  • 1970-01-01
  • 2012-07-18
  • 1970-01-01
  • 1970-01-01
  • 2011-12-08
相关资源
最近更新 更多