美文网首页iOS路上
自定义对象的深拷贝

自定义对象的深拷贝

作者: 海0_0滨 | 来源:发表于2017-09-28 16:10 被阅读1次

    注:一下言论均属个人开发过程中总结,如果有更好的方式活着说的不对,非常感谢朋友能够提出来,必当感谢🙏
    开发过程中遇到这样的问题,一个有很多属性的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,
    第二步:不改变的话可以再复制回来

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

    相关文章

      网友评论

        本文标题:自定义对象的深拷贝

        本文链接:https://www.haomeiwen.com/subject/xvamextx.html