学习笔记1:归档解档、runtime

系统类型

1.归解档字符串

两者都需要先拼出文件路径:
归档

NSString *path = [docPath stringByAppendingPathComponent:@"myStr"];
[NSKeyedArchiver archiveRootObject:@"我是字符串" toFile:path];

解档

NSString *path = [docPath stringByAppendingPathComponent:@"myStr"];
NSString *str = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

2.归解档数组

两者都需要先拼出文件路径:
归档

NSString *path = [docPath stringByAppendingPathComponent:@"myArray"];
[NSKeyedArchiver archiveRootObject:@[@"元素1", @"元素2", @"元素3" toFile:path];

解档

NSString *path = [docPath stringByAppendingPathComponent:@"myArray"];
NSString *str = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

3.归解档字典

两者都需要先拼出文件路径:
归档

NSString *path = [docPath stringByAppendingPathComponent:@"myDic"];
[NSKeyedArchiver archiveRootObject:@{key:value};

解档

NSString *path = [docPath stringByAppendingPathComponent:@"myDic"];
NSString *str = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

自定义类型(两种方法)

例:现有一student学生类具有以下属性:

@property (nonatomic) NSString *name;
@property (nonatomic) NSString *sex;
@property (nonatomic) NSUInteger age;
@property (nonatomic) NSString *school;
@property (nonatomic) BOOL marry;
@property (nonatomic) NSString *className;
@property (nonatomic) NSString *favor;
@property (nonatomic) NSString *skill;
@property (nonatomic) NSString *score;

要想对该学生类实现归档和解档,就一定要实现<NSCoding>协议,该协议中只有两个方法:即要归档的属性和要解档的属性。

方法一:

归档

- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeInteger:_age forKey:@"age"];
    [aCoder encodeObject:_sex forKey:@"sex"];
    [aCoder encodeObject:_favor forKey:@"favor"];
    [aCoder encodeObject:_score forKey:@"score"];
    [aCoder encodeObject:_skill forKey:@"skill"];
    [aCoder encodeObject:_school forKey:@"school"];
    [aCoder encodeObject:_className forKey:@"className"];
    [aCoder encodeBool:_marry forKey:@"marray"];
}

对应的解档

- (instancetype)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.age = [aDecoder decodeIntegerForKey:@"age"];
        self.sex = [aDecoder decodeObjectForKey:@"sex"];
        self.favor = [aDecoder decodeObjectForKey:@"favor"];
        self.score = [aDecoder decodeObjectForKey:@"score"];
        self.skill = [aDecoder decodeObjectForKey:@"skill"];
        self.school = [aDecoder decodeObjectForKey:@"school"];
        self.className = [aDecoder decodeObjectForKey:@"className"];
        self.marry = [aDecoder decodeBoolForKey:@"marray"];
    }
    return self;
}

由于方法一过于单一,遇到属性过多的情况时不能轻松解决,所以需要使用另一种方法来解决(runtime).

方法二:Runtime机制

需要引入runtime库#import <objc/runtime.h>
归档

- (void)encodeWithCoder:(NSCoder *)aCoder{
    // Ivar: 成员变量
    // class_copyIvarList: 拷贝参数一的类的所有属性列表出来,第二参数中会被存入列表中的元素数量
    unsigned int outCount = 0;
    Ivar *varList = class_copyIvarList(self.class, &outCount);
    for (int i = 0; i < outCount; i++) {
        // 从列表中获取每一个成员变量
        Ivar var = varList[i];
        // 获取成员变量的名字
        const char *name = ivar_getName(var);
        // C字符串 -> OC字符串
        NSString *propertyName = [NSString stringWithUTF8String:name];
        NSLog(@"%@", propertyName);
        // KVC
        id value = [self valueForKey:propertyName];
        // 归档
        [aCoder encodeObject:value forKey:propertyName];
    }
    // C语言在用完之后手动进行释放
    free(varList);
}

解档

- (instancetype)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {
            // 1.复制属性列表
        unsigned int outCount = 0;
        Ivar *varList = class_copyIvarList(self.class, &outCount);
            // 2.for循环对每个成员变量进行操作
        for (int i = 0; i < outCount; i++) {
            // 3.获取成员变量名,转换成OC的名字
            Ivar var = varList[i];
            const char *name = ivar_getName(var);
            NSString *pName = [NSString stringWithUTF8String:name];
            // 4.通过属性名解档出对应的值
            id value = [aDecoder decodeObjectForKey:pName];
            // 5.通过KVC方式,把值存储到对应的属性中
            [self setValue:value forKey:pName];
        }

        free(varList);
    }
    return self;
}

可以将description、归档、解档定义为宏。以下以description为例,归档和解档同样定义。

// 宏中的‘\’作用是换行,表示接下来一行也是宏的内容
#define kDescription \
- (NSString *)description{\
    NSMutableString *str = [NSMutableString new];\
    unsigned int outCount = 0;\
    Ivar *varList = class_copyIvarList(self.class, &outCount);\
    for (int i = 0; i < outCount; i++) {\
        Ivar var = varList[i];\
        const char *name = ivar_getName(var);\
        NSString *pName = [NSString stringWithUTF8String:name];\
        id obj = [self valueForKey:pName];\
        [str appendFormat:@"%@:%@", pName, obj];\
    }\
    free(varList);\
    return str;\
}

runtime为系统类添加属性

例:为一个button添加一个name属性,用来存储button的名字。

创建一个UIButton的分类UIButton+Custom,在.h声明一个名字属性
@property (nonatomic) NSString *name;
.m文件中引入#import <objc/runtime.h>,实现setget方法:

- (void)setName:(NSString *)name{
    // 绑定参数3到参数1的键-参数2上, 内存管理的方式是参数4
    // 参数2是方法的指针地址,每个方法的指针地址是唯一的
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name{
    // 获取参数1中key是当前方法的指针对应的值
    // _cmd 可以获取所在的方法指针
    return objc_getAssociatedObject(self, _cmd);
}

更换类型

runtime可以更换对象的类型(OC无法实现的时候)

例:将tableView的类型转换为第三方TPKeyboardAvoidingTableView类型

// 使用runtime替换tableView的类型
// 把参数一的类型变成参数2的类型
object_setClass(self.tableView, [TPKeyboardAvoidingTableView class]);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值