Objective-C:Runtime+自动化归档

Page content

Runtime+NSKeyedArchiver实现自动化归档解档

引言

在实际开发中,我们大部分项目会用到归档解档这一序列化存储数据的方式,对于需要归档的类,少则几个属性,多则十几个二十几个属性,有多少个属性,在归档和解档的代理中就需要添加多少行操作,属性变动后还需要逐行更改,冗长而繁琐。 应用Runtime,我们可以优雅的解决这个问题,使归档解档的init和encode操作自动化。

实例

我们创建要归档的用户类:User interface

~~~objective-c
#import <Foundation/Foundation.h>
@interface User : NSObject
<NSCoding>
@property (nonatomic, strong) NSString * userId;
@property (nonatomic, strong) NSString * userName;
@property (nonatomic, strong) NSString * userAge;
@property (nonatomic, assign) NSString * userSex;
@property (nonatomic, strong) NSString * userPhone;
@property (nonatomic, strong) NSString * userAddress;
@end
~~~

implement

~~~objective-c
#import "User.h"
#import <objc/runtime.h>
@implementation User
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        unsigned int count = 0;
        objc_property_t * property_list = class_copyPropertyList([self class], &count);
        for (unsigned int idx = 0; idx < count; idx ++) {
            objc_property_t property = property_list[idx];
            const char * property_name = property_getName(property);
            NSString * name_str = [NSString stringWithUTF8String:property_name];
            NSString * value = [aDecoder decodeObjectForKey:name_str];
            [self setValue:value forKey:name_str];
        }
        free(property_list);
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    unsigned int count = 0;
    objc_property_t * property_list = class_copyPropertyList([self class], &count);
    for (unsigned int idx = 0; idx < count; idx ++) {
        objc_property_t property = property_list[idx];
        const char * property_name = property_getName(property);
        NSString * name_str = [NSString stringWithUTF8String:property_name];
        id value = [self valueForKey:name_str];
        [aCoder encodeObject:value forKey:name_str];
    }
    free(property_list);
}
@end
~~~

就是这么简单,不需要针对特定属性逐一添加,Runtime自动获取属性列表并逐一对属性进行归档解档,实现自动化,我们来测试一下:

~~~objective-c
/**
 * 归档User
 */
- (IBAction)keyedArchiver:(id)sender {
    User * user = UNGetSerializedObject(KEY_USER);
    if (!user) {
        user = [User new];
    }
    user.userId = @"1001";
    user.userName = @"赵钱孙李";
    user.userAge = @"24";
    user.userSex = @"1";
    user.userPhone = @"18929291100";
    user.userAddress = @"广东省广州市天河区";
    UNSaveSerializedObject(user, KEY_USER);
}

/**
 * 解档User
 */
- (IBAction)keyedUnArchiver:(id)sender {    
    User * user = UNGetSerializedObject(KEY_USER);
    if (user) {
        NSLog(@"user : %@\n, %@\n, %@\n, %@\n, %@\n, %@", user.userId, user.userName, user.userAge, user.userPhone, user.userAddress, user.userSex);
    }
}
~~~

将自动化归结当操作放入基类,或者通过动态方法交换,以Aop的形式写入模型类,那么我们创建的数据模型类就不用进行重复的编解码实现了。