NSObject的copy function如何实现的

morpheus1984 发布于 2013年08月25日 | 更新于 2013年08月26日
无人欣赏。

今天看了下以前写的代码,顺便重新炒了下内存管理的旧饭,突然想知道copy这个函数具体如何实现的。还有对于NSArray NSDictionary等复杂类型对象又是如何处理的。NSString又是什么样的呢?有木有哪位大神能够给写个代码或指导个思路呢 ,@sycx @tinyfool (好吧,这么问可以能太不明确了,我直接写个代码大家看看对不对)

深复制:

- (id)CopyWithZone:(NSZone*)zone
{
      self = [[[self class]allocWithZone:zone]init];
      return self;
}

浅复制:

 - (id)CopyWithZone:(NSZone*)zone
{
   return [self retain];
}
共18条回复
tinyfool 回复于 2013年08月25日

说实话,这类东西我都觉得属于奇技淫巧,能不掺和我就懒得掺和

tinyfool 回复于 2013年08月25日

我喜欢简单省事儿的东西,能不费脑子我就不想费脑子。比如,以前玩COM我就烦引用计数,我写Java那段时间还是觉得GC很幸福。虽然GC会有一定的性能问题,但是我们也把服务器代码的性能调到非常的高。到了Objective-C,引用计数还是很烦人,虽然你知道在手机这种设备上,性能受限,引用计数不得不用。但是能省事儿我还是喜欢省事儿的。

所以我很喜欢ARC。内存管理这套东西我都玩得不是特别好。当然你需要用的时候,你就要去弄好,我当年做Epub reader的时候,性能我还是调校到了很高的程度。当时特意变态的用金庸的全集去跟iBooks比内存占用和分页速度等等。

我不反对学习的时候学深入一点,机理都弄明白,但是用的时候,我反对使用奇技淫巧的东西。很多时候,你可以选择用一些奇技淫巧的东西,也可以选择用一些架构手段去绕过去。或者是去分层,某些非常难懂,但是必要的代码放在一个层次,大量的好懂的代码放在另外一个层次。

当你的项目做到一定大的尺寸以后,你就会发现很多时候高层次的抉择,比具体代码的精妙与否更有价值。比如我们这次移植新杂志到Mac, @sycx 老师本来有点想用大量的分支去处理Mac和iOS的API不兼容性。我本质上担心的是,如果我们平台多了以后,在一个平台上加了新功能,怎么同步到别的代码上去。就觉得他那个方案多半不靠谱。

结果他做了做,发现,光是UIImageNSImage的这点小区别就够他折腾的。于是,我们改成寻找成熟的UIKit Mac版开源实现。结果移植就变得非常容易,迅速就看到了成果,而且可以预期未来两个版本几乎可以同步发行。我们甚至在新杂志的某些大的交互设计上也准备做改动,以便未来iOS和Mac版本可以开发起来更容易。

morpheus1984 回复于 2013年08月25日

启发很大,我回头想想,理下思路。。。

sycx 回复于 2013年08月25日

深复制:

- (id)copyWithZone:(NSZone*)zone
{
      id copy = [[[self class] allocWithZone:zone] init];

      copy.title = [self.title copy];
      copy.name = [self.name copy];

      return self;
}

浅复制:

- (id)copyWithZone:(NSZone*)zone
{
      id copy = [[[self class] allocWithZone:zone] init];

      copy.title = self.title;
      copy.name = self.name;

      return self;
}
nickel 回复于 2013年08月26日
  • (id)CopyWithZone:(NSZone*)zone { return [self retain]; }

这种根本就谈不上是复制,浅个屁啊,明显就是为了省事做的,如果要这样用干嘛要用复制?!既然使用的时候明确是希望copy而不是retain,必然有一定目的。而你这样硬生生地把希望用copy的地方强制为retain,很有可能在使用的时候不小心引入retain cycle之类的不明显问题的。

我个人并不同意tiny对于计数的看法,我觉得技术其实使用起来很轻松,并不会有太多麻烦。当然ARC是为了更省事没错。而且我一直认为,如果是代码逻辑引入的内存问题,ARC也救不了你。

BarryWey 回复于 2013年08月26日

如果对象的属性是『基本数据类型』,就做简单的浅克隆就够了。
如果对象的属性有『其他对象』,那么就要做深度克隆。否则可能会导致两个实例指向同一个对象

morpheus1984 回复于 2013年08月26日

@nickel NSString的copy属性其实就是起到个retain的作用 而NSMutableString则是创建了一个新的内存空间。我写的那两个copyWithZone 其实是为了表达我对浅复制和深复制的理解。NSObject的不同子类对于copyWithZone都有不同的实现

@sycx 不是很明白啊,你在浅复制里面创建了一个对象,那岂不是开辟了新的内存空间?求解释。

tinyfool 回复于 2013年08月26日

@morpheus198 你那个浅复制的代码是不是从某个单例的类的代码里面抄来的?复制当然是要创造新的内存空间啊

ibuick 回复于 2013年08月26日

这些东西去看 GNUstep 的开放源代码,相去不远,可以作为 Cooca 内部实现的重要参考。

ibuick 回复于 2013年08月26日

@tinyfool 研究根本谈不上,好奇的时候会去看,或者有啥不会写不放心的,去参考下。里面的东西很有价值,虽说看不见 Cocoa 源代码,但是很多地方看他参考足够了,

morpheus1984 回复于 2013年08月26日

@tinyfool 我刚才在stackoverflow里面找了下,发现了一个东西,先贴个图给大家看看。详细在这里

这个是我在Stackoverflow里面找到的东西

yelusiku 回复于 2013年08月26日

@ibuick @tinyfool nufound 这个实现也有一定参考价值

tinyfool 回复于 2013年08月26日

NSString是一个非常特殊的类,不能根据NSString的行为去理解所有的类。或者说,你要理解这里的行为,你首先要理解什么是非可变对象和可变对象(mutable)。

非可变对象因为不能变化,实际上,copy的时候就去复用了一个原有的对象,所以才是retain。这就是我说,奇技淫巧的意思。你要理解为什么不同的类的copy实现不同,你不光是要知道字面的东西,你还要知道很多背景知识,在这些不明白之前,光看一点是没用的。

morpheus1984 回复于 2013年08月26日

@tinyfool 补充一下 我写的那个浅复制是参考以前看到的。版权依稀记得是@ibuick的。^_^

tinyfool 回复于 2013年08月26日

还是仔细认真的多看看文档,然后再问问题

还是孔子那句老话,学而不思则惘,思而不学则殆。光看不思考脑子会越来越乱,光思考不看就是白浪费时间。

本帖有18个回复,因为您没有注册或者登录本站,所以,只能看到本帖的10条回复。如果想看到全部回复,请注册或者登录本站。

登录 或者 注册
[顶 楼]
|
|
[底 楼]
|
|
[首 页]