我正在努力澄清一些关于实施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;
}
最好直接编写班级名称[[Crime allocWithZone:zone] init]
还是应该使用[[[self Class] allocWithZone:zone] init]
?
是否可以使用[self month]
复制iVars,还是应该直接访问iVars,_month
?
答案 0 :(得分:96)
您应始终使用[[self class] allocWithZone:zone]
确保使用相应的类创建副本。您为002提供的示例显示了原因:子类将调用[super copyWithZone:zone]
并期望返回相应类的实例,而不是超类的实例。
我直接访问了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,保留它们,还是只是分配它们都应该反映出制定者所做的事情。
答案 1 :(得分:6)
使用SDK提供的对象的copyWithZone:
方法的默认复制行为是"浅拷贝"。这意味着如果您在copyWithZone:
对象上调用NSString
,它将创建浅拷贝而不是深拷贝。浅拷贝和深拷贝之间的区别是:
对象的浅表副本只会复制对原始数组对象的引用,并将它们放入新数组中。
深层复制实际上会复制对象中包含的各个对象。这是通过在自定义类方法中向每个单独的对象发送copyWithZone:
消息来完成的。
INSHORT:要获得浅表副本,请在所有实例变量上调用retain
或strong
。要获得深层复制,请在自定义类copyWithZone:
实现中的所有实例变量上调用copyWithZone:
。现在您可以选择。
答案 2 :(得分:0)
这是我的模特。
#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
答案 3 :(得分:0)
这个实现深层复制的方法如何:
/// 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;
}