Objective-C Realm对象转JSONString

原创文章转载请注明出处

Realm是极好用的移动端数据库,我一直向朋友推荐,不仅仅是因为其跨平台的特性,还因为其自带的自动更新功能让程序结构变得简单。

通常开发中我们会使用ORM框架,将JSON数据映射为对象,在Swift项目里我会用
ObjectMapper进行处理。在老旧的OC项目中,由于历史原因没有使用ORM库,JSON数据自己解析,转换JSONString自然也要自己写。因为iOS自带的NSJSONSerialization可以将NSObject对象转换成NSData,再将NSData转换成NSString即可。

去年将数据库切换成Realm以后,以为所有的RLMObject对象都是继承自NSObject也没太在意,结果昨天尝试将一个RLMObject对象转换成JSONString的时候发现通过NSJSONSerialization转换得到的NSDatanil

跟着代码往下看,发现RLMObject对象的[xxx class]方法返回的Class名称和原对象不一样,前面还带了Realm的前缀,猜测这就是通过反射方法(
class_copyPropertyList)去获取类属性失败的原因。爬了Github和StackOverflow都没有结果,有人报了类似的问题,但是只回复了已解决,却不告知如何解决,这种留图不留种的行为鄙视之。

既然别人可以处理,想来应该也不难。翻一下RLMObject的头文件,找到RLMObjectSchema *objectSchema属性,再从RLMObjectSchema.h文件找到了className属性,打印了一下发现名称正确。既然有了类名,那么NSClassFromString就可以派上用场了。利用NSClassFromString创建Class,然后通过class_copyPropertyList函数获取类型属性,kvc读取对象的属性值,将对象转成NSDictionary,大功告成。

分享一下代码,版权所有,使用时请将头部注释一起拷贝。

//
//  NSObject+JSONCategories.h
//
//  Created by chenjunsheng on 15/4/15.
//  Copyright (c) 2015年 chenjunsheng. All rights reserved.
//

#import 

@interface NSObject (JSONCategories)

- (NSData *)JSONData;
- (NSString *)JSONString;

@end
//
//  NSObject+JSONCategories.m
//
//  Created by chenjunsheng on 15/4/15.
//  Copyright (c) 2015年 chenjunsheng. All rights reserved.
//

#import "NSObject+JSONCategories.h"
#import 

@implementation NSObject (JSONCategories)

- (NSDictionary *)getObjectData {
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    unsigned int propsCount;
 
    Class class = [self class];
    if ([self isKindOfClass:[RLMObject class]]) {
        class = NSClassFromString([[(RLMObject *)self objectSchema] className]);
    }
    objc_property_t *props = class_copyPropertyList(class, &propsCount);//获得属性列表
    for(int i = 0;i < propsCount; i++) {
        objc_property_t prop = props[i];
  
        NSString *propName = [NSString stringWithUTF8String:property_getName(prop)];//获得属性的名称
        id value = [self valueForKey:propName];//kvc读值
        if(value == nil) {
            value = [NSNull null];
        } else {
            value = [value getObjectInternal];//自定义处理数组,字典,其他类
        }
        [dic setObject:value forKey:propName];
    }
    return dic;
}

- (id)getObjectInternal {
    if([self isKindOfClass:[NSString class]]
        || [self isKindOfClass:[NSNumber class]]
        || [self isKindOfClass:[NSNull class]]) {
        return self;
    }
 
    if([self isKindOfClass:[NSArray class]]) {
        NSArray *objarr = (NSArray *)self;
        NSMutableArray *arr = [NSMutableArray arrayWithCapacity:objarr.count];
        for(int i = 0;i < objarr.count; i++) {
            [arr setObject:[[objarr objectAtIndex:i] getObjectInternal] atIndexedSubscript:i];
        }
        return arr;
    }
 
    if([self isKindOfClass:[NSDictionary class]]) {
        NSDictionary *objdic = (NSDictionary *)self;
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:[objdic count]];
        for(NSString *key in objdic.allKeys) {
            [dic setObject:[[objdic objectForKey:key] getObjectInternal] forKey:key];
        }
        return dic;
    }
    return [self getObjectData];
}

- (NSData *)JSONData {
    id obj = [self getObjectInternal];
    if (![NSJSONSerialization isValidJSONObject:obj])
        return nil;
 
    NSError *error = nil;
    NSData *result = [NSJSONSerialization dataWithJSONObject:obj
              options:kNilOptions
                error:&error];
    if(result.length > 0 && error == nil) {
        return result;
    }
    return nil;
}

- (NSString *)JSONString {
    NSData *jsonData = [self JSONData];
    NSString *result = nil;
    if(jsonData) {
        result = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    return result;
}

@end

我是咕咕鸡,一个还在不停学习的全栈工程师。
热爱生活,喜欢跑步,家庭是我不断向前进步的动力。

你可能感兴趣的:(Objective-C Realm对象转JSONString)