1.归档中用到的Runtime,类的属性较多的时候用着比较方便,不用写那么多代码
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface Person : NSObject<NSCoding>
@property (nonatomic ,assign)CGFloat height;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSNumber *age;
@property (nonatomic, assign) int no;
@end
#import "Person.h"
#import <objc/message.h>
#import <objc/runtime.h>
@implementation Person
-(void)encodeWithCoder:(NSCoder *)encoder
{
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([Person 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 = [self valueForKey:key];
[encoder encodeObject:value forKey:key];
}
}
-(instancetype)initWithCoder:(NSCoder *)decoder
{
if (self = [super init]) {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([Person 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 = [decoder decodeObjectForKey:key];
// 设置到成员变量身上
[self setValue:value forKey:key];
}
}
return self;
}
@end
存储文件
//1.创建对象
Person *p=[[Person alloc]init];
p.name=@"??????";
p.age=@23;
p.height = 1.7;
//2.获取文件路径
NSString *docPath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
NSString *path=[docPath stringByAppendingPathComponent:@"person"];
NSLog(@"path=%@",path);
//3.将自定义的对象保存到文件中
[NSKeyedArchiver archiveRootObject:p toFile:path];
读取文件
//1.获取文件路径
NSString *docPath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
NSString *path=[docPath stringByAppendingPathComponent:@"person"];
NSLog(@"path=%@",path);
//2.从文件中读取对象
Person *p=[NSKeyedUnarchiver unarchiveObjectWithFile:path];
2.KVC与归档其实用到Runtime的方法是一样的
两者都是用 Ivar *ivars = class_copyIvarList([Person class], &count);的方法,获取成员变量,
但是还是不建议使用Runtime 获取成员变量 然后在setValue影响性能.
3.分类添加属性
Category
用于给class及其subclass添加新的方法
有自己单独的 .h 和 .m 文件
用于添加新方法,而不能添加新属性(property)
可以用Runtime动态添加属性,下面两种形式都可以为person 添加属性
#import "Person.h"
@interface Person (sex)
@property (nonatomic, strong) NSString *property;
@property (nonatomic, copy) NSString *str;
- (void)nishi;
@end
#import "Person+sex.h"
#import <objc/runtime.h>
static char strKey;
@implementation Person (sex)
- (NSObject *)property {
return objc_getAssociatedObject(self, @selector(property));
}
- (void)setProperty:(NSString *)property {
objc_setAssociatedObject(self, @selector(property), property, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(void)setStr:(NSString *)str
{
objc_setAssociatedObject(self, &strKey, str, OBJC_ASSOCIATION_COPY);
}
-(NSString *)str
{
return objc_getAssociatedObject(self, &strKey);
}
- (void)nishi{
}
@end
注意:(不知道为什么在分类中添加的方法,打印的时候的确是看到添加进去了,但是在用
Ivar *vars = class_copyIvarList([p class], &outCount);
获取成员变量列表的时候,获取不到增加的使用,所以这两种方法在同时使用的时候要注意,但是添加的方法可以打印出来);
unsigned int outCount = 0;
Ivar *vars = class_copyIvarList([p class], &outCount);
// 遍历所有的成员变量
for (int i = 0; i < outCount; i++) {
Ivar ivar = vars[i]; // 取出第i个位置的成员变量
const char *propertyName = ivar_getName(ivar); // 获取变量名
const char *propertyType = ivar_getTypeEncoding(ivar); // 获取变量编码类型
printf("---%s--%s\n", propertyName, propertyType);
}
unsigned int numIvars = 0;
Method *meth = class_copyMethodList([Person class], &numIvars);
for(int i = 0; i < numIvars; i++) {
Method thisIvar = meth[i];
SEL sel = method_getName(thisIvar);
const char *name = sel_getName(sel);
NSLog(@"zp method :%s", name);
}