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
转换得到的NSData
是nil
。
跟着代码往下看,发现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 <Foundation/Foundation.h>
@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 <Realm/Realm.h>
@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
我是咕咕鸡,一个还在不停学习的全栈工程师。
热爱生活,喜欢跑步,家庭是我不断向前进步的动力。