实现 copWithZone 的最佳实践:

我试图在我的脑海中理清一些关于实施 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

49075 次浏览
  1. 应始终使用 [[self class] allocWithZone:zone]来确保使用适当的类创建副本。您为002提供的示例确切地说明了原因: 子类将调用 [super copyWithZone:zone]并期望返回适当类的实例,而不是超类的实例。

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

密码:

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

当然,无论您复制、保留或只是分配这些变量,都应该反映 setter 所做的工作。

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

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

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

INSHORT: 要获得浅拷贝,对所有实例变量调用 retainstrong。要获得深度复制,需要对自定义类 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

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

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