自定义对象的深拷贝
2017-09-28 本文已影响1人
海0_0滨
注:一下言论均属个人开发过程中总结,如果有更好的方式活着说的不对,非常感谢朋友能够提出来,必当感谢🙏
开发过程中遇到这样的问题,一个有很多属性的model对象从上个列表页面传到详情页面展示并可以修改保存,用户在详情页面修改后需要将上个页面的数据同样修改,此时就需要将页面也传过来的model对象的属性值作相应修改。但是可能用户在修改数据后没有点击保存,我们就需要还原原来的model对象值。这时候就需要在进入页面之后我们对原来的model对象做一次深拷贝保存一下。用户修改信息后对copyModel进行修改,点击保存请求成功后,将copymodel的值再复制给model
第一步:通过runtime获取自定义对象的所有属性
导入头文件#import <objc/runtime.h>
/**
通过运行时获取当前对象的所有属性的名称,以数组的形式返回
@return 属性字符串数组
*/
- (NSArray *) allPropertyNames{
///存储所有的属性名称
NSMutableArray *allNames = [[NSMutableArray alloc] init];
///存储属性的个数
unsigned int propertyCount = 0;
///通过运行时获取当前类的属性
objc_property_t *propertys = class_copyPropertyList([self class], &propertyCount);
//把属性放到数组中
for (int i = 0; i < propertyCount; i ++) {
///取出第一个属性
objc_property_t property = propertys[i];
const char * propertyName = property_getName(property);
[allNames addObject:[NSString stringWithUTF8String:propertyName]];
}
///释放
free(propertys);
return allNames;
}
第二步:自定义对象实现<NSMutableCopying>协议并实现
#pragma mark -<NSMutableCopying>
- (id)mutableCopyWithZone:(nullable NSZone *)zone {
CBCCUserCarItemModel *muCopyModel = [[[self class] allocWithZone:zone] init];
//获取实体类的属性名
NSArray *array = [self allPropertyNames];
for (int i = 0; i < array.count; i ++) {
NSString *propertyStr = array[i];
//获取get方法
SEL getSel = NSSelectorFromString(propertyStr);
//获取set方法
NSString *setPropertStr = [NSString stringWithFormat:@"set%@%@:",[[propertyStr substringToIndex:1] uppercaseString],[propertyStr substringFromIndex:1]];
SEL setSel = NSSelectorFromString(setPropertStr);
if ([self respondsToSelector:getSel] && [muCopyModel respondsToSelector:setSel]) {
//获得类和方法的签名
NSMethodSignature *signature = [self methodSignatureForSelector:getSel];
//从签名获得调用对象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
//设置target
[invocation setTarget:self];
//设置selector
[invocation setSelector:getSel];
//接收返回的值
NSObject *__unsafe_unretained returnValue = nil;
//调用
[invocation invoke];
//接收返回值
[invocation getReturnValue:&returnValue];
//调用copymodel的属性set方法,进行赋值
IMP imp = [muCopyModel methodForSelector:setSel];
void (*func)(CBCCUserCarItemModel *,SEL,NSObject *) = (void *)imp;
func(muCopyModel,setSel,returnValue);
// [muCopyModel performSelector:setSel withObject:returnValue];
}
}
return muCopyModel;
}
第三步:在进入详情页页面的时候调用copyModel = [model mutableCopy]
深拷贝创建一个新的对象
如果用户没有点击保存则抛弃这个神拷贝的对象,原model对象没有修改,如果用户保存了数据,则在数据请求结束后,将copyModel的数据复制给model(注意是将属性值复制,不是再次深拷贝)
实现方法类似于👆的代码,只不过不是重新创建,而是将旧的model的属性值替换为新的copyModel的属性值
追加:利用mantle框架
后来在使用mantle框架的时候发现了一个方法- (void)mergeValuesForKeysFromModel:(id<MTLModel>)model
它可以将后面的model的所有属性值复制给调用者
第一步:进入页面后创建一个新的备份copyModel,然后利用合并方法将源model的值全部复制给copyModel,
第二步:不改变的话可以再复制回来