系统类型
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>
,实现set
和get
方法:
- (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]);
网友评论