Iphone 实施copyWithZone时的最佳实践:

Iphone 实施copyWithZone时的最佳实践:,iphone,objective-c,cocoa-touch,copywithzone,Iphone,Objective C,Cocoa Touch,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]];

我正试图弄清楚关于实现
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;
}
在001年:
  • 最好直接编写类名
    [[Crime allocWithZone:zone]init]
    还是使用
    [[self class]allocWithZone:zone]init]

  • 使用
    [self month]
    复制IVAR可以吗,还是应该直接访问IVAR,即
    \u month

  • 您应该始终使用
    [[self class]allocWithZone:zone]
    来确保使用适当的类创建副本。您为002给出的示例确切地说明了为什么:子类将调用
    [super copyWithZone:zone]
    ,并期望返回相应类的实例,而不是超级类的实例

  • 我直接访问IVAR,因此我不需要担心以后可能会添加到属性设置器中的任何副作用(例如,生成通知)。请记住,子类可以自由重写任何方法。在您的示例中,每个ivar发送两条额外消息。我将按以下方式实施:

  • 代码:


    当然,无论您是复制IVAR、保留IVAR,还是仅仅分配IVAR,都应该反映setter的工作。

    SDK提供的对象的
    copyWithZone:
    方法的默认复制行为是“浅复制”。这意味着,如果在
    NSString
    对象上调用
    copyWithZone:
    ,它将创建浅拷贝,但不会创建深拷贝。浅拷贝和深拷贝的区别是:

    对象的浅层副本将仅复制对原始数组对象的引用,并将其放置到新数组中

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

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

    这是我的型号

    #import <Foundation/Foundation.h>
    @interface RSRFDAModel : NSObject
    
    
    @property (nonatomic, assign) NSInteger objectId;
    
    @property (nonatomic, copy) NSString *name;
    
    @property (nonatomic, strong) NSArray<RSRFDAModel *> *beans;
    
    
    @end
    
    
    #import "RSRFDAModel.h"
    
    @interface RSRFDAModel () <NSCopying>
    
    @end
    
    @implementation RSRFDAModel 
    
    
    -(id)copyWithZone:(NSZone *)zone {
        RSRFDAModel *model = [[[self class] allocWithZone:zone] init];
    
        model.objectId = self.objectId;
        model.name = self.name;
        model.beans = [self.beans mutableCopy];
    
        return model;
    }
    
    @end
    
    #导入
    @接口RSRFDAModel:NSObject
    @属性(非原子,赋值)NSInteger objectId;
    @属性(非原子,副本)NSString*名称;
    @属性(非原子,强)NSArray*豆;
    @结束
    #导入“RSRFDAModel.h”
    @接口RSRFDAModel()
    @结束
    @RSRFDAModel的实现
    -(id)copyWithZone:(NSZone*)区{
    RSRFDAModel*model=[[[self class]allocWithZone:zone]init];
    model.objectId=self.objectId;
    model.name=self.name;
    model.beans=[self.beans mutableCopy];
    收益模型;
    }
    @结束
    
    这个实现深度复制的怎么样:

    /// Class Foo has two properties: month and category
    - (id)copyWithZone:(NSZone *zone) {
        Foo *newFoo;
        if ([self.superclass instancesRespondToSelector:@selector(copyWithZone:)]) {
            newFoo = [super copyWithZone:zone];
        } else {
            newFoo = [[self.class allocWithZone:zone] init];
        }
        newFoo->_month = [_month copyWithZone:zone];
        newFoo->_category = [_category copyWithZone:zone];
        return newFoo;
    }
    

    选择这两种方法中的哪一种取决于超类是否实现了
    NSCopying
    。例如,
    NSObject
    没有,因此调用
    [super-copyWithZone:zone]
    将抛出一个异常。它说/Users/ws403216/Desktop/Demo/Demo/Crime.m:21:28:No-visible@interface For'NSObject'声明了选择器“copyWithZone:”super-class of-Crime.m在我的例子中是NSObject.@NitinMalguri,正如前面的评论所指出的,如果父类支持NSCopying,则只应调用
    [super copyWithZone:zone]
    ,否则应调用
    [[self class]allocWithZone:zone]init]
    并根据需要复制字段。默认复制行为应为浅复制,但您提供了深复制的解决方案。浅复制和深复制的区别在于:对象的浅复制只会复制对原始数组对象的引用,并将它们放置到新数组中。深度复制实际上会复制对象中包含的各个对象。通过向每个对象发送“copyWithZone:”消息,可以澄清误解
    /// Class Foo has two properties: month and category
    - (id)copyWithZone:(NSZone *zone) {
        Foo *newFoo;
        if ([self.superclass instancesRespondToSelector:@selector(copyWithZone:)]) {
            newFoo = [super copyWithZone:zone];
        } else {
            newFoo = [[self.class allocWithZone:zone] init];
        }
        newFoo->_month = [_month copyWithZone:zone];
        newFoo->_category = [_category copyWithZone:zone];
        return newFoo;
    }