主要目的是为了记录
问题描述:
通常对于需要实现对模型的拷贝都需要先实现model的 NSCopying,NSMutableCopying协议。但这里存在一个问题:对于包含model(实现copy协议的)的数组使用拷贝操作,只会对数组本身进行拷贝,数组的内的model不会进行copy。
一。实现模型数组深拷贝的方法:
1.归档解档实现数组内部元素拷贝。
对model使用 归档的话,model的遵循NSCoding协议且实现协议。
@interface DataModel : NSObject<NSCoding,NSCopying,NSMutableCopying>
@property (nonatomic , copy) NSString * title;
@property (nonatomic , copy) NSString * subTitle;
@property (nonatomic , copy) NSString * detail;
@property (nonatomic , copy) NSString * icon;
@property (nonatomic , assign) float cellHeigjt;
@property (nonatomic , strong) NSArray<SubModel *>* subModelArray;
@property (nonatomic , strong) SubModel * subModel;
@end
@implementation DataModel
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"subModelArray":@"SubModel"};
}
- (id)initWithCoder: (NSCoder *)coder
{
if (self = [super init])
{
self.title = [coder decodeObjectForKey:@"title"];
self.subTitle = [coder decodeObjectForKey:@"subTitle"];
self.detail = [coder decodeObjectForKey:@"detail"];
self.icon = [coder decodeObjectForKey:@"icon"];
self.cellHeigjt = [coder decodeFloatForKey:@"cellHeigjt"];
self.subModelArray = [coder decodeObjectForKey:@"subModelArray"];
self.subModel = [coder decodeObjectForKey:@"subModel"];
}
return self;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
[coder encodeObject:self.title forKey:@"title"];
[coder encodeObject:self.subTitle forKey:@"subTitle"];
[coder encodeObject:self.detail forKey:@"detail"];
[coder encodeObject:self.icon forKey:@"icon"];
[coder encodeFloat:self.cellHeigjt forKey:@"cellHeigjt"];
[coder encodeObject:self.subModelArray forKey:@"subModelArray"];
[coder encodeObject:self.subModel forKey:@"subModel"];
}
NSArray * trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:@[dataModel]]];
所得的数组以及数组内的model都是深copy。
2.系统方法:(推荐使用)
- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag
NSMutableArray * array = [NSMutableArray arrayWithArray:@[model,model1]];
NSArray *lastArray = [[NSArray alloc]initWithArray:array copyItems:YES];
所得的数组以及数组内的model都是深copy。
二。结合runtime的特性以及模型数组深拷贝的方法,我们可以实现model的多层次数组模型的copy。
@interface DataModel : NSObject<NSCopying,NSMutableCopying>
@property (nonatomic , copy) NSString * title;
@property (nonatomic , copy) NSString * subTitle;
@property (nonatomic , copy) NSString * detail;
@property (nonatomic , copy) NSString * icon;
@property (nonatomic , assign) float cellHeigjt;
@property (nonatomic , strong) NSArray<SubModel *>* subModelArray;
@property (nonatomic , strong) SubModel * subModel;
@end
@implementation DataModel
//##下面代码你只需要更换下model的类型,可直接复用。(在使用的地方需要导入 #import <objc/message.h>)
-(id)copyWithZone:(NSZone *)zone{
id objCopy = [[[self class] allocWithZone:zone] init];
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
const char *name = property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:name];
id value = [self valueForKey:propertyName];
if (value&&([value isKindOfClass:[NSMutableArray class]]||[value isKindOfClass:[NSArray class]])) {
id valueCopy = [[NSArray alloc]initWithArray:value copyItems:YES];
[objCopy setValue:valueCopy forKey:propertyName];
}else if (value) {
[objCopy setValue:[value copy] forKey:propertyName];
}
}
free(properties);
return objCopy;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
id objCopy = [[[self class] allocWithZone:zone] init];
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
const char *name = property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:name];
id value = [self valueForKey:propertyName];
if (value&&([value isKindOfClass:[NSMutableArray class]]||[value isKindOfClass:[NSArray class]])) {
id valueCopy = [[NSMutableArray alloc]initWithArray:value copyItems:YES];
[objCopy setValue:valueCopy forKey:propertyName];
}else if(value){
[objCopy setValue:[value copy] forKey:propertyName];
}
}
free(properties);
return objCopy;
}
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"subModelArray":@"SubModel"};
}
@end
@interface SubModel : NSObject<NSCopying,NSMutableCopying>
@property (nonatomic , copy) NSString *title;
@property (nonatomic , copy) NSString *subTitle;
@property (nonatomic , copy) NSString *text;
@property (nonatomic , copy) NSString *url;
@property (nonatomic , assign) float cellHeigjt;
@property (nonatomic , strong) ThridModel *thrid;
@property (nonatomic , strong) NSArray<ThridModel*> *thridArray;
@property (nonatomic , strong) NSArray<ThridModel*> *thridSubArray;
@end
@implementation SubModel
+(NSDictionary *)mj_objectClassInArray
{
return @{@"thridArray":@"ThridModel"};
}
-(id)copyWithZone:(NSZone *)zone{
id objCopy = [[[self class] allocWithZone:zone] init];
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
const char *name = property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:name];
id value = [self valueForKey:propertyName];
if (value&&([value isKindOfClass:[NSMutableArray class]]||[value isKindOfClass:[NSArray class]])) {
id valueCopy = [[NSMutableArray alloc]initWithArray:value copyItems:YES];
[objCopy setValue:valueCopy forKey:propertyName];
}else if(value){
[objCopy setValue:[value copy] forKey:propertyName];
}
}
free(properties);
return objCopy;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
id objCopy = [[[self class] allocWithZone:zone] init];
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
const char *name = property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:name];
id value = [self valueForKey:propertyName];
if (value&&([value isKindOfClass:[NSMutableArray class]]||[value isKindOfClass:[NSArray class]])) {
id valueCopy = [[NSMutableArray alloc]initWithArray:value copyItems:YES];
[objCopy setValue:valueCopy forKey:propertyName];
}else if(value){
[objCopy setValue:[value copy] forKey:propertyName];
}
}
free(properties);
return objCopy;
}
@end
DataModel * dataModel = [DataModel mj_objectWithKeyValues:dict2] ;
DataModel * copyDataModel = [dataModel copy];
到此就实现了对model的直接copy,不管model里面是否含有包含其他model的数组。拷贝后,都能得到一个全新的model。