iOS路上

自定义对象的深拷贝

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,
第二步:不改变的话可以再复制回来

上面的方法感觉总有些不尽人意,但是能力有限暂无其他方法,期待大神能给更好的建议,小弟将不胜感激

上一篇下一篇

猜你喜欢

热点阅读