当前位置:   article > 正文

Runtime详解及应用_anycontrol runtime系统架构

anycontrol runtime系统架构

一、运行时机制

  • 动态语言:编译时确定变量的数据类型。
  • 静态语言:运行时确定变得的数据类型。

1、【动态语言】:Objective-C语言(以下简称“OC”)是一门动态语言,其优势有:代码编程更灵活,如可以将消息转成给我们想要的对象,或者随意交换一个方法的实现等。

2、【编译器 + 运行时操作系统】:OC作为动态语言,其需要编译器运行时系统来执行编译的代码,而这个运行时系统就是我所要讲的Objc Runtime(Runtime)。Runtime本身是一个,它基本上是用C和汇编写的,有了这个库使得C语言有面向对象的能力。

3、【函数的调用区别】:C语言,在编译的时候决定调用哪个函数;OC语言,在运行的时候决定调用哪个函数。

4、【在编译阶段报错】:OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错;C语言调用未实现的函数就会报错。

二、应用

  • 1、 能获得某个类的所有成员变量
  • 2、能获得某个类的所有属性
  • 3、能获得某个类的所有方法
  • 4、交换方法实现
  • 5、能动态添加一个成员变量
  • 6、能动态添加一个属性
  • 7、字典转模型
  • 8、runtime归档/解档

图一

Demo点击下载

三、基本函数和头文件

#import<objc/runtime.h> : //成员变量,类,方法
class_copyIvarList : 获得某个类内部的所有成员变量
class_copyMethodList : 获得某个类内部的所有方法
class_getInstanceMethod : 获得某个具体的实例方法 (对象方法,减号-开头)
class_getClassMethod : 获得某个具体的类方法 (加号+开头)
method_exchangeImplementations : 交换两个方法的实现
#import<objc/message.h> : //消息机制
objc_msgSend(...)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

四、应用

1、更改属性值
#import <Foundation/Foundation.h>
@interface ZMPerson : NSObject
/** 姓名 **/
@property (nonatomic, copy) NSString *name;
/** 性别 **/
@property (nonatomic, copy) NSString *sex;

- (NSString *)coding;
- (NSString *)eating;
- (NSString *)changeMethod;

@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
#import "ZMPerson.h"
#import <objc/runtime.h>
@interface ZMPerson(){
    NSString *mobile;//手机号
}

/** 年龄 **/
@property (nonatomic, copy) NSString *age;

@end

@implementation ZMPerson{
    NSString *address;//地址
}

- (NSString *)coding {
    return @"coding";
}

- (NSString *)eating {
    return @"eating";
}

- (NSString *)changeMethod {
    return @"方法已被拦截并替换";
}

// void(*)()
// 默认方法都有两个隐式参数,
void eat(id self, SEL _cmd, NSNumber *meter){
    NSLog(@"%@ __ %@ __ %@",[self class],NSStringFromSelector(_cmd),meter);
}

// 当一个对象调用未实现的方法,会调用这个方法处理,并且会把对应的方法列表传过来.
// 刚好可以用来判断,未实现的方法是不是我们想要动态添加的方法
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    NSString *selStr = @"eat:";
    SEL selFromStr = NSSelectorFromString(selStr);
    if (sel == selFromStr) {
        // 动态添加eat方法
        // 第一个参数:给哪个类添加方法
        // 第二个参数:添加方法的方法编号
        // 第三个参数:添加方法的函数实现(函数地址)
        // 第四个参数:函数的类型,(返回值+参数类型) v:void @:对象->self :表示SEL->_cmd
        class_addMethod(self, sel, (IMP)eat, "v@:@");
    }
    return [super resolveInstanceMethod:sel];
}

@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
#import "ZMPerson.h"
@interface ZMFirstVC ()
@property (nonatomic, strong) ZMPerson *person;
@end
@implementation ZMFirstVC

- (void)initView {
    [super initView];
    _person = [ZMPerson new];
}

- (void)buttonClick:(UIButton *)sender {
    // ------   设置属性值   -----
    _person.sex = @"1";
    unsigned int count = 0;
    // 动态获取类中的所有属性(包括私有)
    Ivar *ivar = class_copyIvarList(_person.class, &count);
    // 遍历属性找到对应字段
    for (int i = 0; i < count; i ++) {
        Ivar tempIvar = ivar[i];
        //ivar_getName:将IVar变量转化为字符串
        const char *varChar = ivar_getName(tempIvar);
        //ivar_getTypeEncoding:获取IVar的类型
        //const char *memberType = ivar_getTypeEncoding(tempIvar);
        NSString *varString = [NSString stringWithUTF8String:varChar];

        if ([varString isEqualToString:@"_name"]) {
            // 修改对应的字段值
            object_setIvar(_person, tempIvar, @"姓名");
        }

        NSLog(@"----->%@",varString);
        //私有类
        if ([varString isEqualToString:@"_age"]) {
            object_setIvar(_person, tempIvar, @"100");
        }

        //私有类
        if ([varString isEqualToString:@"address"]) {
            object_setIvar(_person, tempIvar, @"福建省厦门市");
        }
        //私有类
        if ([varString isEqualToString:@"mobile"]) {
            object_setIvar(_person, tempIvar, @"138****8888");
        }
    }

    // ----  利用KVC键值编码 获取属性值   -----
    NSString *str0 = [_person valueForKey:@"_name"];
    NSString *str1 = [_person valueForKey:@"_sex"];
    NSString *str2 = [_person valueForKey:@"_age"];
    NSString *str3 = [_person valueForKey:@"address"];
    NSString *str4 = [_person valueForKey:@"mobile"];
    NSMutableString *mstr = [NSMutableString string];
    [mstr appendString:str0];
    [mstr appendString:str1];
    [mstr appendString:str2];
    [mstr appendString:str3];
    [mstr appendString:str4];
    NSLog(@"非私有类:%@__%@\n私有类:%@__%@__%@__",str0,str1,str2,str3,str4);
    self.testLabelText = mstr ? mstr : @"更改属性值失败";
    // -----  键值编码设置属性值   ------
    [_person setValue:@"我的家乡还是在福建啊" forKey:@"address"];
    NSLog(@"=======%@", [_person valueForKey:@"address"]);
}
@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

执行结果:
图二

2、动态添加属性
#import <Foundation/Foundation.h>
@interface NSObject (ZMAddAttribute_h)
@property (nonatomic, copy) NSString *name;
@end



#import "NSObject+ZMAddAttribute_h.h"
#import <objc/message.h>

@implementation NSObject (ZMAddAttribute_h)

-(void)setName:(NSString *)name{
    objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(NSString *)name{
    return objc_getAssociatedObject(self, @"name");
}

@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
#import "NSObject+ZMAddAttribute_h.h"
@interface ZMSecondVC ()
@property (nonatomic, strong) NSObject *person;
@end

@implementation ZMSecondVC

- (void)initView {
    [super initView];
    _person = [NSObject new];
    _person.name = @"添加属性成功";
}
- (void)buttonClick:(UIButton *)sender {
    self.testLabelText = _person.name.length ? _person.name : @"添加属性失败";
}
@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
3、添加方法成功
#import "ZMPerson.h"
@interface ZMThirdVC ()
@property (nonatomic, strong) ZMPerson *person;
@end

@implementation ZMThirdVC

- (void)initView {
    [super initView];
    _person = [ZMPerson new];
}

- (void)buttonClick:(UIButton *)sender {
    /*
     动态添加 coding 方法
     (IMP)codingOC 意思是 codingOC 的地址指针;
     "v@:" 意思是,v 代表无返回值 void,如果是 i 则代表 int;@代表 id sel; : 代表 SEL _cmd;
     “v@:@@” 意思是,两个参数的没有返回值。
     */
    class_addMethod([_person class], @selector(test), (IMP)codingObjC, "v@:");
    // 调用 coding 方法响应事件
    if ([_person respondsToSelector:@selector(test)]) {
        [_person performSelector:@selector(test)];
        self.testLabelText = @"添加方法成功";
    }else{
        self.testLabelText = @"添加方法失败";
    }
    [_person performSelector:@selector(eat:) withObject:@100 afterDelay:3];
}

-(void)test{
    NSLog(@"测试测试");
}

// 方法实现
void codingObjC(id self,SEL _cmd){
    NSLog(@"添加方法成功");
}
@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
4、交换方法实现
#import "ZMPerson.h"
@interface ZMFourthVC ()
@property (nonatomic, strong) ZMPerson *person;
@end

@implementation ZMFourthVC

- (void)initView {
    [super initView];
    _person = [ZMPerson new];
    NSLog(@"%@",_person.coding);
    NSLog(@"%@",_person.eating);   
}

- (NSArray *)buttonTitleArray {
    return @[@"交换", @"不交换"];
}

- (void)buttonClick:(UIButton *)sender {
    if (sender.tag == 0) {
        [self exchangeMethod];
    }
    NSString *str = [NSString stringWithFormat:@"%@_%@",[_person coding],[_person eating]];
    self.testLabelText = str;
    NSLog(@"%@",_person.coding);
    NSLog(@"%@",_person.eating);
}

///交换方法
-(void)exchangeMethod{
    Method aMethod = class_getInstanceMethod([_person class], @selector(coding));
    Method bMethod = class_getInstanceMethod([_person class], @selector(eating));
    method_exchangeImplementations(aMethod, bMethod);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
5、拦截并替换方法
#import <objc/runtime.h>

@interface NSObject (Swizzle)

///拦截替换方法
+ (BOOL)swizzleMethod:(SEL)origSel withMethod:(SEL)aftSel;

@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
@implementation NSObject (Swizzle)

///拦截替换方法
+ (BOOL)swizzleMethod:(SEL)origSel withMethod:(SEL)aftSel {
    Method originMethod = class_getInstanceMethod(self, origSel);
    Method newMethod = class_getInstanceMethod(self, aftSel);
    if(originMethod && newMethod) {//必须两个Method都要拿到
        if(class_addMethod(self, origSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
            //实现成功添加后
            class_replaceMethod(self, aftSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
        }
        return YES;
    }
    return NO;
}

@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
#import "NSObject+Swizzle.h"
@implementation MyString

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = object_getClass((id)self);
        [class swizzleMethod:@selector(resolveInstanceMethod:) withMethod:@selector(myResolveInstanceMethod:)];
    });
}

+ (BOOL)myResolveInstanceMethod:(SEL)sel {
    if(! [self myResolveInstanceMethod:sel]) {
//        NSString *selString = NSStringFromSelector(sel);
//        class_addMethod(self, sel, class_getMethodImplementation(self, @selector(dynamicMethodIMP)), "v@:");
//        return YES;
        NSString *selString = NSStringFromSelector(sel);
        ///锁定一些方法如果不存在则创建
        if([selString isEqualToString:@"countAll"] || [selString isEqualToString:@"pushViewController"] || [selString isEqualToString:@"test"]) {
            class_addMethod(self, sel, class_getMethodImplementation(self, @selector(dynamicMethodIMP)), "v@:");
            return YES;
        }else {
            return NO;
        }
    }
    return YES;
}

- (void)dynamicMethodIMP {
    NSLog(@"我是动态加入的函数");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
- (void)buttonClick:(UIButton *)sender {
    NSLog(@"begin test");
    MyString *string = [[MyString alloc] init];
    [string performSelector:@selector(countAll)];
    [string performSelector:@selector(pushViewController)];
    [string performSelector:@selector(test)];
    NSLog(@"finish test");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
6、在方法上添加额外功能
@interface ZMCountButton : UIButton

@property (nonatomic, assign) NSInteger count;

@end


@interface ZMClickCount : NSObject

+ (instancetype)sharedInstance;

- (NSInteger)clickCount;

@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
#import <objc/runtime.h>

@implementation ZMCountButton

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method oriMethod = class_getInstanceMethod(self.class, @selector(sendAction:to:forEvent:));
        Method cusMethod = class_getInstanceMethod(self.class, @selector(customSendAction:to:forEvent:));
        // 判断自定义的方法是否实现, 避免崩溃
        BOOL addSuccess = class_addMethod(self.class, @selector(sendAction:to:forEvent:), method_getImplementation(cusMethod), method_getTypeEncoding(cusMethod));
        if (addSuccess) {
            // 没有实现, 将源方法的实现替换到交换方法的实现
            class_replaceMethod(self.class, @selector(customSendAction:to:forEvent:), method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
        } else {
            // 已经实现, 直接交换方法
            method_exchangeImplementations(oriMethod, cusMethod);
        }
    });
}

- (void)customSendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
    _count = [[ZMClickCount sharedInstance] clickCount];
    [self customSendAction:action to:target forEvent:event];
}

@end



@interface ZMClickCount()

@property (nonatomic, assign) NSInteger count;

@end

@implementation ZMClickCount

+ (instancetype)sharedInstance {
    static ZMClickCount *_instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

- (NSInteger)clickCount {
    ++_count;
    NSLog(@"点击了 %ld次", _count);
    return _count;
}

@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
- (void)countButtonClick:(UIButton *)sender {
    self.testLabelText = [NSString stringWithFormat:@"点击 %ld 次了", self.testButton.count];
}

#pragma mark - 懒加载
- (ZMCountButton *)testButton {
    if (!_testButton) {
        _testButton = [ZMCountButton buttonWithType:UIButtonTypeCustom];
        [_testButton addTarget:self action:@selector(countButtonClick:) forControlEvents:UIControlEventTouchUpInside];
        [_testButton setTitle:@"统计此按钮的点击数量" forState:UIControlStateNormal];
        _testButton.frame = CGRectMake(20, self.view.center.y + 100, [UIScreen mainScreen].bounds.size.width - 40, 30);
        _testButton.backgroundColor = [UIColor redColor];
    }
    return _testButton;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
7、字典转模型
#import <Foundation/Foundation.h>
@protocol ModelDelegate <NSObject>
@optional
// 用在三级数组转换
+ (NSDictionary *)arrayContainModelClass;
@end
@interface NSObject (NNKeyValues)

/** 字典转模型 **/
+ (instancetype)modelWithDict:(NSDictionary *)dict;
@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
#import "NSObject+ZMKeyValues.h"
#import <objc/runtime.h>

@implementation NSObject (ZMKeyValues)

/** 字典转模型 **/
+ (instancetype)modelWithDict:(NSDictionary *)dict {
    id objc = [[self alloc] init];
    unsigned int count = 0;
    // 获取成员属性数组
    Ivar *ivarList = class_copyIvarList(self, &count);
    // 遍历所有的成员属性名
    for (int i = 0; i < count; i ++) {
        // 获取成员属性
        Ivar ivar = ivarList[i];
        // 获取成员属性名
        NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
        NSString *key = [ivarName substringFromIndex:1];
        // 从字典中取出对应 value 给模型属性赋值
        id value = dict[key];
        // 获取成员属性类型
        NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
        // 判断 value 是不是字典
        if ([value isKindOfClass:[NSDictionary class]]) {
            ivarType = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""];
            ivarType = [ivarType stringByReplacingOccurrencesOfString:@"\"" withString:@""];
            Class modalClass = NSClassFromString(ivarType);
            // 字典转模型
            if (modalClass) {
                // 字典转模型
                value = [modalClass modelWithDict:value];
            }
        }
        if ([value isKindOfClass:[NSArray class]]) {
            // 判断对应类有没有实现字典数组转模型数组的协议
            if ([self respondsToSelector:@selector(arrayContainModelClass)]) {
                // 转换成id类型,就能调用任何对象的方法
                id idSelf = self;
                // 获取数组中字典对应的模型
                NSString *type = [idSelf arrayContainModelClass][key];
                // 生成模型
                Class classModel = NSClassFromString(type);
                NSMutableArray *arrM = [NSMutableArray array];
                // 遍历字典数组,生成模型数组
                for (NSDictionary *dict in value) {
                    // 字典转模型
                    id model =  [classModel modelWithDict:dict];
                    [arrM addObject:model];
                }
                // 把模型数组赋值给value
                value = arrM;
            }
        }
        // KVC 字典转模型
        if (value) {
            [objc setValue:value forKey:key];
        }
    }
    return objc;
}

@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
- (void)initView {
    [super initView];
    NSDictionary *person = @{@"name":@"Chen",
                             @"sex": @"男"};
    NSDictionary *dict = @{@"coderID":@"99",
                           @"nickName": @"rattanchen",
                           @"phoneNumber": @"138****8888",
                           @"person" : person};
    NSArray *addarr = @[dict ,dict, dict];
    NSMutableDictionary *mudict = [NSMutableDictionary dictionaryWithDictionary:dict];
    [mudict setObject:person forKey:@"person"];

    for (NSDictionary *item in addarr) {
        ZMCoding *coding = [ZMCoding modelWithDict:item];
        [self.dataArray addObject:coding];
    }
    if (self.dataArray.count) {
        self.testLabelText = @"字典转模型成功, 点击查看对应的值";
    }
}

- (void)buttonClick:(UIButton *)sender {
    ZMCoding *coding = self.dataArray.firstObject;
    switch (sender.tag) {
        case 0:
            self.testLabelText = coding.coderID;
            break;
        case 1:
            self.testLabelText = coding.nickName;
            break;
        case 2:
            self.testLabelText = coding.phoneNumber;
            break;
        case 3:
            self.testLabelText = coding.person.name;
            break;
        case 4:
            self.testLabelText = coding.person.sex;
            break;
        default:
            break;
    }
}

- (NSArray *)buttonTitleArray {
    return @[@"ID", @"昵称", @"手机号", @"姓名", @"性别"];
}

- (NSMutableArray *)dataArray {
    if (!_dataArray) {
        _dataArray = [NSMutableArray array];
    }
    return _dataArray;
}
@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
8、归档解档
#import <Foundation/Foundation.h>
#import "NSObject+ZMKeyValues.h"
#import "ZMPerson.h"

@interface ZMCoding : NSObject<NSCoding>

@property (nonatomic, strong) ZMPerson *person;

@property (nonatomic, copy) NSString *coderID;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, copy) NSString *phoneNumber;
@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
#import <objc/runtime.h>

@implementation ZMCoding

- (void)encodeWithCoder:(NSCoder *)aCoder {
    unsigned int count = 0;
    // 获取类中所有属性
    Ivar *ivars = class_copyIvarList(self.class, &count);
    // 遍历属性
    for (int i = 0; i < count; i ++) {
        // 取出 i 位置对应的属性
        Ivar ivar = ivars[i];
        // 查看属性
        const char *name = ivar_getName(ivar);
        NSString *key = [NSString stringWithUTF8String:name];
        // 利用 KVC 进行取值,根据属性名称获取对应的值
        id value = [self valueForKey:key];
        [aCoder encodeObject:value forKey:key];
    }
    free(ivars);
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        unsigned int count = 0;
        // 获取类中所有属性
        Ivar *ivars = class_copyIvarList(self.class, &count);
        // 遍历属性
        for (int i = 0; i < count; i ++) {
            // 取出 i 位置对应的属性
            Ivar ivar = ivars[i];
            // 查看属性
            const char *name = ivar_getName(ivar);
            NSString *key = [NSString stringWithUTF8String:name];
            // 进行解档取值
            id value = [aDecoder decodeObjectForKey:key];
            // 利用 KVC 对属性赋值
            [self setValue:value forKey:key];
        }
    }
    return self;
}

@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
- (void)initView {
    [super initView];
    ZMCoding *coding = [ZMCoding new];
    coding.coderID = @"99";
    coding.nickName = @"rattanchen";
    coding.phoneNumber = @"138****8888";

    NSString *path = [ZMTools getDomainsPathWithFile:@"123"];
    BOOL isSuc = [NSKeyedArchiver archiveRootObject:coding toFile:path];
    if (isSuc == YES) {
        self.testLabelText = @"归档成功, 点击按钮取出模型中对应的值";
    }else{
        self.testLabelText = @"归档失败";
    }
}

- (void)buttonClick:(UIButton *)sender {
    NSString *path = [ZMTools getDomainsPathWithFile:@"123"];
    ZMCoding *coding = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    coding.coderID = @"999";
    if (sender.tag == 0) {
        self.testLabelText = coding.coderID;
    } else if (sender.tag == 1) {
        self.testLabelText = coding.nickName;
    } else {
        self.testLabelText = coding.phoneNumber;
    }
}

- (NSArray *)buttonTitleArray {
    return @[@"ID", @"昵称", @"手机号"];
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

Demo点击下载

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/428344
推荐阅读
相关标签
  

闽ICP备14008679号