iOS 自定义模型拷贝、传值

2,844 阅读2分钟

项目修改的过程中出现一个自定义模型传值问题导致的bug,现记录一下方便以防以后再次出现同样的问题。

两个界面A,B(A页面push到B页面)同时将A的model传递到下一个页面,直接使用 B.model = model;

这样的话,A和B的model是同一块内存,会出现当在B修改了model后,A的model也随之改变,这样从B返回到A页面的时候会出现model值被改变的问题。

B的model地址

A的model地址

可以注意到两个model指向同一个地址, 因此解决办法可以想到copy出一份model然后再传给B。

解决办法

- (id)copyWithZone:(NSZone *)zone {
    TestModel * model = [[self class] allocWithZone:zone];
    model.name = _name.copy;
    return model;
}

但是项目中自定义的模型有很多,如果一个一个属性进行赋值,这样很不方便,不适合向我这样爱偷懒的,于是想有没有其他取巧方法。通过查询一些资料得知,可以采用runtime动态修改模型值来入手,于是出现了如下解决方案。

要在自定义模型里添加如下代码,当然不要忘记遵守< NSCopying >协议

- (id)copyWithZone:(NSZone *)zone {
    TestModel *model = [[TestModel 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) {
            [model setValue:value forKey:propertyName];
        }
    }
    free(properties);
    return model;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
    TestModel *model = [[TestModel 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) {
            [model setValue:value forKey:propertyName];
        }
    }
    free(properties);
    return model;
}

解决方法再升级

注意到我们的项目中使用了YYModel,因此我们也可以采用如下方法解决

- (id)copyWithZone:(NSZone *)zone {
    return [self yy_modelCopy];
}

在控制器里使用

使用传值的时候直接.copy就可以了

好了,这个问题到此就解决了。