今天看了下以前写的代码,顺便重新炒了下内存管理的旧饭,突然想知道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];
}
我喜欢简单省事儿的东西,能不费脑子我就不想费脑子。比如,以前玩COM我就烦引用计数,我写Java那段时间还是觉得GC很幸福。虽然GC会有一定的性能问题,但是我们也把服务器代码的性能调到非常的高。到了Objective-C,引用计数还是很烦人,虽然你知道在手机这种设备上,性能受限,引用计数不得不用。但是能省事儿我还是喜欢省事儿的。
所以我很喜欢ARC。内存管理这套东西我都玩得不是特别好。当然你需要用的时候,你就要去弄好,我当年做Epub reader的时候,性能我还是调校到了很高的程度。当时特意变态的用金庸的全集去跟iBooks比内存占用和分页速度等等。
我不反对学习的时候学深入一点,机理都弄明白,但是用的时候,我反对使用奇技淫巧的东西。很多时候,你可以选择用一些奇技淫巧的东西,也可以选择用一些架构手段去绕过去。或者是去分层,某些非常难懂,但是必要的代码放在一个层次,大量的好懂的代码放在另外一个层次。
当你的项目做到一定大的尺寸以后,你就会发现很多时候高层次的抉择,比具体代码的精妙与否更有价值。比如我们这次移植新杂志到Mac, @sycx 老师本来有点想用大量的分支去处理Mac和iOS的API不兼容性。我本质上担心的是,如果我们平台多了以后,在一个平台上加了新功能,怎么同步到别的代码上去。就觉得他那个方案多半不靠谱。
结果他做了做,发现,光是UIImage
和NSImage
的这点小区别就够他折腾的。于是,我们改成寻找成熟的UIKit Mac版开源实现。结果移植就变得非常容易,迅速就看到了成果,而且可以预期未来两个版本几乎可以同步发行。我们甚至在新杂志的某些大的交互设计上也准备做改动,以便未来iOS和Mac版本可以开发起来更容易。
深复制:
- (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;
}
这种根本就谈不上是复制,浅个屁啊,明显就是为了省事做的,如果要这样用干嘛要用复制?!既然使用的时候明确是希望copy而不是retain,必然有一定目的。而你这样硬生生地把希望用copy的地方强制为retain,很有可能在使用的时候不小心引入retain cycle之类的不明显问题的。
我个人并不同意tiny对于计数的看法,我觉得技术其实使用起来很轻松,并不会有太多麻烦。当然ARC是为了更省事没错。而且我一直认为,如果是代码逻辑引入的内存问题,ARC也救不了你。
@nickel NSString的copy属性其实就是起到个retain的作用 而NSMutableString则是创建了一个新的内存空间。我写的那两个copyWithZone 其实是为了表达我对浅复制和深复制的理解。NSObject的不同子类对于copyWithZone都有不同的实现
@sycx 不是很明白啊,你在浅复制里面创建了一个对象,那岂不是开辟了新的内存空间?求解释。
NSString是一个非常特殊的类,不能根据NSString的行为去理解所有的类。或者说,你要理解这里的行为,你首先要理解什么是非可变对象和可变对象(mutable)。
非可变对象因为不能变化,实际上,copy的时候就去复用了一个原有的对象,所以才是retain。这就是我说,奇技淫巧的意思。你要理解为什么不同的类的copy实现不同,你不光是要知道字面的东西,你还要知道很多背景知识,在这些不明白之前,光看一点是没用的。