实现copyWithZone时的最佳实践:

fuz*_*oat 74 iphone cocoa-touch objective-c copywithzone

我试图澄清一些关于实施的问题copyWithZone:,任何人都可以评论以下内容......

// 001: Crime is a subclass of NSObject.
- (id)copyWithZone:(NSZone *)zone {
    Crime *newCrime = [[[self class] allocWithZone:zone] init];
    if(newCrime) {
        [newCrime setMonth:[self month]];
        [newCrime setCategory:[self category]];
        [newCrime setCoordinate:[self coordinate]];
        [newCrime setLocationName:[self locationName]];
        [newCrime setTitle:[self title]];
        [newCrime setSubtitle:[self subtitle]];
    }
    return newCrime;
}

// 002: Crime is not a subclass of NSObject.
- (id)copyWithZone:(NSZone *)zone {
    Crime *newCrime = [super copyWithZone:zone];
    [newCrime setMonth:[self month]];
    [newCrime setCategory:[self category]];
    [newCrime setCoordinate:[self coordinate]];
    [newCrime setLocationName:[self locationName]];
    [newCrime setTitle:[self title]];
    [newCrime setSubtitle:[self subtitle]];
    return newCrime;
}
Run Code Online (Sandbox Code Playgroud)

在001中:

  1. 最好是直接编写类名[[Crime allocWithZone:zone] init]还是应该使用[[[self Class] allocWithZone:zone] init]

  2. 是否可以[self month]用于复制iVars或者我应该直接访问iVars,即_month

Ton*_*ony 98

  1. 您应始终使用[[self class] allocWithZone:zone]以确保使用适当的类创建副本.您为002提供的示例显示了原因:子类将调用[super copyWithZone:zone]并期望获取相应类的实例,而不是超类的实例.

  2. 我直接访问ivars,所以我不需要担心稍后可能会添加到属性设置器的任何副作用(例如,生成通知).请记住,子类可以自由地覆盖任何方法.在您的示例中,您每个ivar发送两条额外消息.我会按如下方式实现它:

码:

- (id)copyWithZone:(NSZone *)zone {
    Crime *newCrime = [super copyWithZone:zone];
    newCrime->_month = [_month copyWithZone:zone];
    newCrime->_category = [_category copyWithZone:zone];
    // etc...
    return newCrime;
}
Run Code Online (Sandbox Code Playgroud)

当然,无论是复制ivars,保留它们,还是仅仅分配它们都应该反映出setter的作用.

  • 选择哪两种方法取决于超类是否实现了"NSCopying".例如,`NSObject`没有,因此调用`[super copyWithZone:zone]`会抛出异常. (33认同)
  • @NitinMalguri正如之前的评论指出的那样,如果父类支持NSCopying,你应该只调用`[super copyWithZone:zone]`,否则你应该调用`[[[self class] allocWithZone:zone] init]`并将字段复制为需要. (10认同)
  • 默认复制行为应该是浅拷贝,但您提供了深拷贝的解决方案.浅拷贝和深拷贝之间的区别是:对象的浅拷贝只会复制对原始数组对象的引用,并将它们放入新数组中.深层复制实际上将复制对象中包含的各个对象.这是通过向每个单独的对象发送"copyWithZone:"消息来完成的. (2认同)

Tri*_*ent 6

copyWithZone:SDK提供的对象的方法的默认复制行为是"浅拷贝".这意味着,如果你调用copyWithZone:NSString对象,它会创建一个浅表副本,但不深拷贝.浅拷贝和深拷贝之间的区别是:

对象的浅表副本只会复制对原始数组对象的引用,并将它们放入新数组中.

深层复制实际上将复制对象中包含的各个对象.这是通过copyWithZone:在自定义类方法中向每个单独的对象发送消息来完成的.

INSHORT:要获得浅拷贝,您可以调用retain或调用strong所有实例变量.要获得深层复制,请调用copyWithZone:自定义类copyWithZone:实现中的所有实例变量.现在您可以选择.