美文网首页
补充YYModel无法直接关联CoreData的缺点

补充YYModel无法直接关联CoreData的缺点

作者: Ginhoor | 来源:发表于2019-01-02 14:58 被阅读0次

    好久没写博文了,18年真是忙碌的一年,一眨眼居然就19年了,居然空了一年没写,今年先开个好头吧,整理一下去年的积累。

    JSON转Model是一个很长常见,又非常繁琐的技术方案,好在现在有很多第三方库支援,让我们不用重复造轮子。博主一直都喜欢用Mantle框架,无奈Mantle框架的model定义过于繁琐,尤其是类型转换。于是就转投了YYModel的怀抱,在此感谢下YYModel的作者(https://github.com/ibireme/YYModel)。

    YYModel有一个一直未实现的,就是Model和CoreData的关联转换。于是借鉴Mantle的思路,我自己造了个轮子,虽然不是快,胜在能用,也还有不少不足,希望大家能帮我补充提点下

    思路是这样的,Model实现YYModel协议后已经有了JSON转换功能,现在再增加上Model转换NSManagedObject的功能,就可以实现JSON转换成NSManagedObject。

    为了实现低耦合,选择协议的方式来实现,首先定义一个协议

    @protocol CEYYModelCoreData <NSObject>
    
    // 关联NSManagedObjectEntity的名字
    + (NSString *)managedObjectEntityName;
    
    // 指明 NSManagedObjectEntity 中表示关系的字段
    + (NSDictionary <NSString *, id> *)managedRelationshipPropertyMapper;
    
    // 指明 NSManagedObjectEntity 中集合字段的类型
    + (NSDictionary <NSString *, id> *)managedRelationshipContainerPropertyMapper;
    
    @end
    

    实现参考

    + (NSString *)managedObjectEntityName
    {
        return [NSString stringWithFormat:@"%@Managed",NSStringFromClass([self class])];
    }
    
    + (NSDictionary <NSString *, id> *)managedRelationshipPropertyMapper
    {
        return @{@"auditStatus":[CEAuditStatusEnum class],
        @"loanApplicationFileList":[NSArray class],
        @"vehicleList":[NSArray class]};
    }
    
    + (NSDictionary <NSString *, id> *)managedRelationshipContainerPropertyMapper
    {
        return @{@"loanApplicationFileList":[CELoanFile class],
                 @"vehicleList":[CEVehicle class]};
    }
    

    这个协议的作用是描述Model和NSManagedObjectEntity之间的转化关系。
    接下去就是如何转换的问题了,这里我碰到了一个问题:NSManagedObjectEntity存储如SQLite的时候,CoreData会为这条数据添加一个自增的主键id,但是这个id无法在NSManagedObjectEntity结构体中获得,所以我添加了一个NSString类型的UUID来作为这条数据的唯一标识符。

    下面是进行转换

    - (void)setValuesByManagedObj:(NSManagedObject *)obj
    {
        // 获得Entity中的字段名
        NSArray *attributesKeys = [[[obj entity] attributesByName] allKeys];
        // 根据字段名获得对应值
        NSDictionary *attributeDic = [obj dictionaryWithValuesForKeys:attributesKeys];
        // 将值设置给Model
        [self yy_modelSetWithJSON:attributeDic];
        
        // 获得Entity的关联关系
        NSArray<NSString *> *relationshipsKeys = [[[obj entity] relationshipsByName] allKeys];
        // 判断关联关系是否存在
        if (relationshipsKeys.count > 0) {
            // 获取关联关系的对应转换
            NSDictionary *relationshipDic = [(id<CEYYModelCoreData>)[self class] managedRelationshipPropertyMapper];
            
            [relationshipsKeys enumerateObjectsUsingBlock:^(NSString * _Nonnull key, NSUInteger idx, BOOL * _Nonnull stop) {
                if ([relationshipDic.allKeys containsObject:key]) {
                    Class relationshipClass = relationshipDic[key];
                    
                    //判断是否为容器类型
                    if ([relationshipClass isSubclassOfClass:[NSArray class]] ||
                        [relationshipClass isSubclassOfClass:[NSSet class]] ||
                        [relationshipClass isSubclassOfClass:[NSOrderedSet class]]
                        ) {
                        // 获取关联关系中容器的对应转换
                        NSDictionary *relationshipContainerDic = [(id<CEYYModelCoreData>)[self class] managedRelationshipContainerPropertyMapper];
                        
                        if ([relationshipContainerDic.allKeys containsObject:key]) {
                            
                            Class relationshipContainerClass = relationshipContainerDic[key];
                            // 获得Entity中的容器内容
                            NSArray <NSManagedObject *> *managedObjList = [obj valueForKey:key];
                            // 将关系中的元素转换成对应类型
                            id result = [managedObjList bk_map:^id(NSManagedObject *managedObj) {
                                CEBaseYYModel *containerObj = [[relationshipContainerClass alloc] init];
                                [containerObj setValuesByManagedObj:managedObj];
                                
                                return containerObj;
                            }];
    
                            NSString *newKey = key;
                            //默认转换key为对应关系的Key,如果使用YYModel定义了kKey转换关系,则会被替换成YYModel中的Key
                            if ([self respondsToSelector:@selector(modelCustomPropertyMapper)]) {
                                NSDictionary *modelCustomPropertyMapper = [(id<YYModel>)[self class] modelCustomPropertyMapper];
                                if ([modelCustomPropertyMapper.allValues containsObject:key]) {
                                    newKey = modelCustomPropertyMapper.allKeys[[modelCustomPropertyMapper.allValues indexOfObject:key]];
                                }
                            }
                            // 将转换好的元素设置到Model中
                            [self setValue:result forKey:newKey];
                        }
                    } else {
                        // 从Entity中获取对应值设置给Model
                        NSManagedObject *managedObj = [obj valueForKey:key];
                        CEBaseYYModel *containerObj = [[relationshipClass alloc] init];
                        [containerObj setValuesByManagedObj:managedObj];
                        [self setValue:containerObj forKey:key];
                    }
                }
            }];
        }
    }
    

    其中重要思路是先获得NSManagedObject中的字段与关联关系,先转换字段,然后根据Model实现CEYYModelCoreData协议中的关联关系定义来转换容器类型字段

    这里只是解决常见CoreData关联关系转换,根据实际情况,还有很多扩展可以做。
    我封装了一个简单的BaseModel类供大家参考(https://github.com/ginhoor/CEBaseYYModel

    相关文章

      网友评论

          本文标题:补充YYModel无法直接关联CoreData的缺点

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