2013-04-05 25 views
3

在某些情况下(例如,挂钩到内部进行测试时),能够创建不采用NSCopying(不实现-copyWithZone:)的类的实例副本将会很方便。这怎么能实现? (注意:在一个类中实现该协议是不够的,因为并不是所有类的实例变量都在其头部中可见)。如何为不采用NSCopying的类创建对象实例的副本?

我试过遍历对象的Ivar s,(1)对于递归(或保留)的对象类型,以及(2)对于基元类型,获得原始实例d中的伊娃的地址和正在进行的拷贝以及从源伊娃的地址开始到目的伊娃的地址的缓冲区。

@interface NSObject (ADDLCopy) 

- (id)addl_generateCopyDeep:(BOOL)deepCopy; 

@end 

@implementation NSObject (ADDLCopy) 

//modified from http://stackoverflow.com/a/12265664/1052673 
- (void *)addl_ivarPointerForName:(const char *)name 
{ 
    void *res = NULL; 

    Ivar ivar = class_getInstanceVariable(self.class, name); 

    if (ivar) { 
     res = (void *)self + ivar_getOffset(ivar); 
    } 

    return res; 
} 


- (id)addl_generateCopyDeep:(BOOL)deepCopy; 
{ 
    id res = [[self.class alloc] init]; 

    unsigned int count = 0; 
    Ivar *ivars = class_copyIvarList(self.class, &count); 
    for (unsigned int i = 0; i < count; i++) { 
     Ivar ivar = ivars[i]; 
     //We need to try here because of a bug with NSGetSizeAndAlignment 
     //which prevents bitfields from being handled properly and results 
     //in an exception being thrown. See this link for more discussion: 
     //http://lists.apple.com/archives/cocoa-dev/2008/Sep/msg00883.html 
     @try { 
      NSUInteger size = 0; 
      const char *encoding = ivar_getTypeEncoding(ivar); 
      NSGetSizeAndAlignment(encoding, &size, NULL); 
      char firstEncodingCharacter[2]; 
      strncpy(firstEncodingCharacter, encoding, 1); 
      firstEncodingCharacter[1] = 0; 
      if (strcmp(firstEncodingCharacter, "@") == 0) { 
       if (deepCopy) { 
        id original = object_getIvar(self, ivar); 
        id copy = [original addl_generateCopyDeep:deepCopy]; 
        object_setIvar(res, ivar, copy); 
       } else { 
        id original = object_getIvar(self, ivar); 
        object_setIvar(res, ivar, original); 
       } 
      } else { 
       const char *name = ivar_getName(ivar); 
       void *bytesSource = [self addl_ivarPointerForName:name]; 
       void *bytesTarget = [res addl_ivarPointerForName:name]; 
       memcpy(bytesTarget, bytesSource, size); 
      } 
     } 
     @catch (NSException *exception) {} 
     @finally {} 
    } 
    free(ivars); 

    return res; 
} 

@end 

这有些作用,但有一些突出的问题,我知道,更不用说那些我不知道。首先,它不复制从超类继承的ivars。其次,它不适用于收藏。另外,由于a bug in NSGetSizeAndAlignment,它不适用于位掩码。此外,它不考虑关联的对象。

如何递归地复制对象的实例(以及它拥有的所有对象)?如果这不是完全可能的(处理一个被保留并存储在空指针中的拥有对象似乎相当困难,甚至可能),在什么程度上可以完成?

回答

8

总之,你不能。

“深度”复制是一个极其领域特定的问题。

例如,你是复制一个对象的delegate还是将delegate的副本指向同一个对象(或者将其设置为零,并要求复制客户端设置它)?

对于这个例子,关于复制的每上下文业务逻辑大约有十亿个其他一次性位(这就是为什么“深度复制”的概念未在集合类上实现的原因)。

而且以上全部假设你实际上都有实现细节。对于框架中实现的类,无法安全地复制它们,因为根本没有可用的数据甚至不知道需要复制哪些内存位,更不用说如何复制。

您需要限制复制操作的范围和定义,然后寻求解决方案。

相关问题