为什么在实现NSCopying时,zone参数总是nil?

15

这可能是一个简单的问题,但为什么在我的类中实现NSCopying协议时,我会得到zone == nil呢?

- (id)copyWithZone:(NSZone *)zone
{
    if (zone == nil)
        NSLog(@"why this is allways nil");

    (...)
}

这被称为使用该方法复制包含对象的数组。

[[NSArray alloc] initWithArray:myArray copyItems:YES]];
5个回答

25

Kevin和Robin的回答是最准确的。Oscar的回答也非常接近正确。但是,Gnustep文档和logancautrell关于zones存在的原因并不完全正确。

创建zone最初是为了确保从单个zone分配的对象在内存中相对连续,这是真实的。事实证明,这并没有减少应用程序使用的内存量;在大多数情况下,它会稍微增加。

更大的目的是能够批量销毁一组对象。

例如,如果您将一个复杂的文档加载到基于文档的应用程序中,在关闭文档时撤销对象图可能会非常昂贵。

因此,如果文档的所有对象都从一个单独的zone分配,而该zone的分配元数据也在该zone中,则与文档相关的所有对象的销毁成本将与仅销毁zone一样便宜(这真的很便宜--“系统,有这些页面” - 一个函数调用)。

这被证明是行不通的。如果指向区域之外的对象的单个引用泄漏出区域,则在关闭文档并且对象无法告诉任何引用它的东西停止时,应用程序将立即崩溃。其次,该模型还遭受了在GC系统中经常遇到的“稀缺资源”问题。也就是说,如果文档的对象图保存了非内存资源,则在销毁zone之前没有有效清理这些资源的方法。

最后,由于所有增加的脆弱性并没有带来足够的性能提升(您有多少次会关闭复杂的文档),因此zones是一个糟糕的想法。尽管如此,API已无法更改,我们只能留下残余物。


太棒了,我正希望你能回答这个问题。顺便问一下,在苹果文档中是否有记录此内容?今天我只能找到NSZone*基础方法。 - logancautrell
3
如果您有类似的问题需要我关注,请在 Twitter 上 @bbum 我。语言和操作系统的演变真的很迷人。如果有记录的话,可能还是在 Rhapsody 时代留下的。我不认为在 Mac OS X 正式版本中曾经建议使用“zones”。 - bbum
1
非常感谢您的贴文,由于您独特的地位和经历,这些帖子受到高度重视。我希望有更多的苹果工程师在这里花时间! - logancautrell

4

NULL区域只是指“使用默认区域”。现代Objective C运行时不再使用区域,并且不能与ARC一起使用。

请参见文档


3

NSZone 已经被废弃很久了。它仍然存在于方法签名中(例如 +allocWithZone:-copyWithZone:),是为了保持向后兼容。


1
如果copyWithZone已被弃用(在NSCopying协议定义中没有提到),那么如何在现今实现需要的copyWithZone:方法来实现NSCopying? - Marcin
3
-copyWithZone: 没有被弃用,只有 NSZone 被弃用了。忽略掉 zone 参数即可。 - Lily Ballard

1

Zone是一个遗留问题,它来自于计算机只有8兆字节或更少的RAM的旧时代。

请查看(3.1.2内存分配和区域):

http://www.gnustep.org/resources/documentation/Developer/Base/ProgrammingManual/manual_3.html

关于这个问题,10年前Cocoa Builder(当时是Cocoa Dev邮件列表)上有一个很好的讨论。这正是@bbum所说的。

http://www.cocoabuilder.com/archive/cocoa/65056-what-an-nszone.html

显然,这曾经在苹果文档中有记录,但自2007-06-06以来已经发生了变化。

http://www.cocoadev.com/index.pl?NSZone


1

NSZone现在是一个未记录的类,因为它相当古老,其目的是使用相同的虚拟内存页面在堆上分配对象。然而,它现在大多数情况下不再使用,但由于它以前被使用过,该参数仍然存在以保持向后兼容性。


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