79

我正试图澄清一些关于实施的事情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 中:

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

  2. 可以[self month]用于复制 iVar 还是我应该直接访问 iVar _month

4

4 回答 4

103
  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;
}

当然,无论您是复制 ivars、保留它们,还是仅仅分配它们,都应该反映 setter 所做的事情。

于 2012-03-28T13:02:25.647 回答
6

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

对象的浅拷贝只会复制对原始数组对象的引用并将它们放入新数组中。

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

INSHORT :要获得浅拷贝,您调用retainstrong在所有实例变量上。要获得深层副本,您需要调用copyWithZone:自定义类copyWithZone:实现中的所有实例变量。现在是您的选择。

于 2015-04-15T15:06:51.457 回答
1

这个实现深拷贝的怎么样:

/// 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;
}
于 2017-08-08T03:18:16.470 回答
-1

这是我的模型。

#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
于 2016-08-12T07:29:52.120 回答