转自: http://hi.baIDu.com/yezehui2002/blog/item/8c328299f0c3631e6e068c8b.HTML
在 C++ 中,定义复制运算符和相关的 *** 作是很重要的。在 Objective-C 中,运算法是不允许重定义的,所能做的就是要求提供一个正确的复制函数。
克隆 *** 作在 Cocoa 中要求使用 NScopying 协议实现。该协议要求一个实现函数:
- ( ID ) copyWithZone : @H_419_26@NSZone * )zone;这个函数的参数是一个内存区,用于指明需要复制那一块内存。Cocoa 允许使用不同的自定义区块。大多数时候默认的区块就已经足够,没必要每次都单独指定。幸运的是,NSObject 有一个函数
) copy;封装了 copyWithZone:,直接使用默认的区块作为参数。但它实际相当于 NScopying 所要求的函数。另外,NScopyObject() 提供一个不同的实现,更简单但同样也需要注意。下面的代码没有考虑 NScopyObject():
// 如果父类没有实现 copyWithZone:,并且没有使用 NScopyObject() )zone { // 创建对象 Foo * clone = [ [Foo allocWithZone :zone ] init ]; // 实例数据必须手动复制 clone ->integer = self ->integer; // "integer" 是 int 类型的 // 使用子对象类似的机制复制 clone ->objectToClone [self ->objectToClone copyWithZone // 有些子对象不能复制,但是可以共享 clone ->objectToShare ->objectToShare retain // 如果有设置方法,也可以使用 [clone setobject :self ->object ]; return clone; }注意,我们使用的是 allocWithZone: 而不是 alloc。alloc 实际上封装了 allocWithZone:,它传进的是默认的 zone。但是,我们应该注意父类的 copyWithZone: 的实现。
// 父类实现了 copyWithZone:,并且没有使用 NScopyObject() { Foo [super copyWithZone // 创建新的对象 // 必须复制当前子类的实例数据 clone NScopyObject()NSObject 事实上并没有实现 NScopying 协议(注意函数的原型不同),因此我们不能简单地使用 [super copy...] 这样的调用,而是类似 [[... alloc] init] 这种标准调用。NScopyObject() 允许更简单的代码,但是需要注意指针变量(包括对象)。这个函数创建一个对象的二进制格式的拷贝,其原型是:
// extraBytes 通常是 0,可以用于索引实例数据的空间 ID NScopyObject @H_419_26@ID anObject, unsigned int extraBytes,0)">*zone )二进制复制可以复制非指针对象,但是对于指针对象,需要时刻记住它会创建一个指针所指向的数据的新的引用。通常的做法是在复制完之后重置指针。
// 如果父类没有实现 copyWithZone: = NScopyObject (self, 0,zone ); // 以二进制形式复制数据 // clone->integer = self->integer; // 不需要,因为二进制复制已经实现了 // 需要复制的对象成员必须执行真正的复制 clone // 共享子对象必须注册新的引用 [clone // 设置函数看上去应该调用 clone->object. 但实际上是不正确的, // 因为这是指针值的二进制复制。 // 因此在使用 mutator 前必须重置指针 clone ->object = nil; } // 如果父类实现了 copyWithZone: // 父类实现 NScopyObject() 了吗? // 这对于知道如何继续下面的代码很重要 clone // 仅在 NScopyObject() 没有使用时调用 // 如果有疑问,一个需要复制的子对象必须真正的复制 clone // 不管 NScopyObject() 是否实现,新的引用必须添加 clone ]; clone @H_419_26@nil; // 如果有疑问,最好重置 Dummy-cloning,mutability,mutablecopy and mutablecopyWithZone:如果需要复制不可改变对象,一个基本的优化是假装它被复制了,实际上是返回一个原始对象的引用。从这点上可以区分可变对象与不可变对象。
不可变对象的实例数据不能被修改,只有初始化过程能够给一个合法值。在这种情况下,使用“伪克隆”返回一个原始对象的引用就可以了,因为它本身和它的复制品都不能够被修改。此时,copyWithZone: 的一个比较好的实现是:
// 返回自身,增加一个引用 return [self retain ]; retain *** 作意味着将其引用加 1。我们需要这么做,因为当原始对象被删除时,我们还会持有一个复制品的引用。“伪克隆”并不是无关紧要的优化。创建一个新的对象需要进行内存分配,相对来说这是一个比较耗时的 *** 作,如果可能的话应该注意避免这种情况。这就是为什么需要区别可变对象和不可变对象。因为不可变对象可以在复制 *** 作上做文章。我们可以首先创建一个不可变类,然后再继承这个类增加可变 *** 作。Cocoa 中很多类都是这么实现的,比如 NSMutableString 是 Nsstring 的子类;NSMutableArray 是 NSArray 的子类;NSMutableData 是 NSData 的子类。
然而根据我们上面描述的内容,似乎无法从不可变对象安全地获取一个完全的克隆,因为不可变对象只能“伪克隆”自己。这个限制大大降低了不可变对象的可用性,因为它们从“真实的世界”隔离了出来。
除了 NScopy 协议,还有一个另外的 NSMutablecopying 协议,其原型如下:
) mutablecopyWithZone mutablecopyWithZone: 必须返回一个可变的克隆,其修改不能影响到原始对象。类似 NSObject 的 copy 函数,也有一个 mutablecopy 函数使用默认区块封装了这个 *** 作。mutablecopyWithZone: 的实现类似前面的 copyWithZone: 的代码: // 如果父类没有实现 mutablecopyWithZone: // 或者可用 NScopyObject() clone // 类似 copyWithZone:,有些子对象需要复制,有些需要增加引用 // 可变子对象使用 mutablecopyWithZone: 克隆 //... 不要忘记我们可以使用父类的 mutablecopyWithZone: // 如果父类实现了 mutablecopyWithZone: [super mutablecopyWithZone } 总结以上是内存溢出为你收集整理的典型 cloning, copy, copyWithZone:, NSCopyObject()全部内容,希望文章能够帮你解决典型 cloning, copy, copyWithZone:, NSCopyObject()所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)