这两个NSString方法的区别

7

我今天在面试中被问到了这个问题,经过一番搜索后,我仍然无法找到答案(事实上,我甚至找不到任何使用[NSString string]方法的代码)。

下面是两种方式的区别:

  1. NSString *someString = [NSString string];
  2. NSString *someString = [[NSString alloc] init];

起初我认为[NSString string]会返回一个自动释放的对象,而使用alloc和init则会返回一个保留的对象。然而,这个答案似乎是错误的。

我查看了苹果文档中的NSString类参考,但它只是说:

Returns an empty string.

+ (id)string 

Return Value
An empty string.

有人可以向我解释一下这两者之间的确切区别吗?它们是什么意思?

3
如果这是你没有得到工作的_唯一_原因,那似乎有点不公平。 - jrturton
1
在iOS5(使用ARC)中,它们是相同的东西。 - beryllium
@jrturton 这只是我被问到的众多问题之一,我不认为这将是我是否能够通过面试阶段的唯一原因。 - Jason
5个回答

5

您的回答是否是这样的,并且您是否询问了为什么您的答案不正确?我之所以问这个问题是因为您的假设在更高的层面上基本上是正确的。

当从alloc+init返回时,它并不完全保留,而是一个您拥有一次引用的对象,并且应该使用releaseautorelease进行平衡。对于方便构造器(+[NSString string]),您会得到一个对象,您对其没有任何引用,但可以期望它在当前自动释放池弹出之前存活,除非您发送了显式的retain(假设使用MRC或ARC,因为其标记为iOS)。

在较低的级别上,您可能会猜测一些内容,但我不希望在许多objc面试中出现这种问题(除非您告诉他们您是中高级水平)。基本上,它是实现定义的,但两种形式都可以返回相同的静态常量NSString(这可能是面试官正在寻找的内容)。例如:

@implementation NSString

static NSString * const EmptyNSString = @"";

- (id)init
{
    self = [super init];
    [self release];
    return EmptyNSString;
}

+ (id)string
{
    return EmptyNSString;
}

...

再次强调,这是实现定义的,但是一个明显的优化。此外,该优化使得对于可变变体(NSMutableString),在某些情况下,物理子类化具体不可变类型(NSString)变得困难。


感谢您的回复,Justin。实际上我并没有询问是否答案不正确,因为我们在面试时时间有点紧迫。但是他们问我是否确定我的答案是正确的,并告诉我再次查看问题,我一脸困惑地看着他们,然后我们就继续进行了。 - Jason
@Jason 哦,好的。所以问题可能已经得到了令人满意的回答,他们想知道你是否知道我概述的优化(或者可能是其他什么)。 - justin
@JeremyP 为什么不呢?...或者你是指我在编辑中澄清的一点吗? - justin
1
@Justin:看到我的回答就知道为什么不行了。不过,重新阅读你的回答后,我觉得我给你的负评有点过分,所以我撤销了它。 - JeremyP
@JeremyP 好的,沿途我措辞不够准确,后来意识到并进行了更新。 - justin

4
正确答案是:
NSString *someString = [NSString string];

给你一个空字符串,但它不属于你,你不能释放它(根据内存管理规则)

然而

NSString *someString = [[NSString alloc] init];

给你一个空字符串,你需要自己拥有并根据内存管理规则释放。

不了解具体实现,你无法对这两个字符串做出其他任何评价。你不能说它们是自动释放的,因为它们可能不是,而且你也无法确定保留计数是多少。

事实上,在这两种情况下,你可能会得到指向某个NSString子类的常量对象的相同指针,该对象的保留计数可能为UINT_MAX,这是运行时用作禁用常量字符串的正常保留释放行为的标志。我没有实际尝试上述内容,因为除了Objective-C SDK的维护者之外,没有人需要关心。


感谢您的回复,Jeremy,并让我了解了UINT_MAX标志。 - Jason
@Jason:UINT_MAX是一个实现细节。通常情况下,你不需要了解它。 - JeremyP
是的,我明白。但也许这只是我的小习惯,我喜欢了解那些你通常无法从课本上学到的微妙细节。 - Jason

4
我的初始想法是[NSString string]将返回一个被自动释放的对象。从技术上讲,它是一个常量占位符字符串,即在整个程序执行期间都存在,从未被释放。它不是一个自动释放的字符串。从概念上讲,这是我作为面试官关注的重点。它是一个字符串(空字符串),不属于调用者拥有,因此调用者不应该释放它。
而使用alloc和init则会返回一个已被保留的对象。从技术上讲,它是一个常量占位符字符串,即在整个程序执行期间都存在。实际上,它和上面的对象是相同的,并且没有被保留。从概念上讲,这是我作为面试官关注的重点。它是一个字符串(空字符串),由调用者拥有,因此调用者在不再需要它时负责释放它。

由于这是一个关于面试的问题,我将把它标记为正确答案,因为它似乎解释了面试官期望的答案。谢谢Bevarious。 - Jason

0

你不经常看到

NSString *someString = [NSString string]; 

因为它与之前的相同

NSString *someString = @""; 

这是一个比较短的方法,通常用于创建一个空的NSMutableString。

NSMutableString* s = [NSMutableString string];

这两个语句的意思确实完全相同,没有任何背景干扰吗?我问这个问题是因为我很好奇NSString类为什么会有一个永远不会被实际使用的字符串方法? - Jason
请注意,+[NSString string] 返回的常量空字符串与 @"" 不是同一个对象。 - user557219
在NSMutableString* s = [NSMutableString string];的情况下,它非常有用。 - jbat100
能否请那位点踩的人解释一下,在什么情况下 NSString *someString = [NSString string]; 的行为实际上会与 NSString *someString = @""; 不同? - jbat100
[NSString string] 是一个自动释放的空字符串,同样的,@"" 也是(无论你怎么想,即使在“技术上”、“底层实现”上并非如此,这只是一些实现细节)。 - jbat100
两者都没有被自动释放。另外,你的回答没有显示下投票。O_o - user557219

0
我能想到的唯一可能是:
  1. 不会分配内存,因为它不是使用alloc创建的。它是由系统创建的常量(一个空字符串),不需要释放。

  2. 你自己为NSString分配内存,这意味着当你完成后必须跟踪NSString是否仍然存在,并且因此需要释放它。


1
即使+[NSString alloc]不分配内存,它也会返回一个类型为NSPlaceholderString的占位符单例。这是在实现类簇时的常见模式。 - user557219

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接