a.对象归档
//解档
//每次头文件都需要导入#import <objc/runtime.h>,每次都需要free,因为在Xcode中创建,没法自动释放C语言的内容,所以需要手动去做,第一个Ivar *ivars是要遍历出所有的这个类,而第二次不加*是因为只是取的其中一个实际的变量值。
#import "Student.h"
#import <objc/runtime.h>
- (void)encodeWithCoder:(NSCoder *)aCoder{
/**
* 获得一个类的实例列表
*/
unsigned int count = 0;
//取出所有的实例变量
Ivar *ivars = class_copyIvarList([Student class], &count);
for (int i = 0; i < count; i ++) {
//指的是本身自己
Ivar ivar = ivars[i];
const char *name = ivar_getName(ivar);
NSString *ocName = [NSString stringWithUTF8String:name];
id value = [self valueForKey:ocName];
[aCoder encodeObject:value forKey:ocName];
}
free(ivars);
}
//归档
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
unsigned int count = 0;
if (self = [super init]) {
Ivar *ivars = class_copyIvarList([Student class], &count);
for (int i = 0; i < count; i ++) {
//指的是本身自己
Ivar ivar = ivars[i];
const char *name = ivar_getName(ivar);
NSString *ocName = [NSString stringWithUTF8String:name];
id value = [aDecoder decodeObjectForKey:ocName];
[self setValue:value forKey:ocName];
}
free(ivars);
}
return self;
}
#import "UIViewController+Swizzing.h"
#import <objc/runtime.h>
@implementation UIViewController (Swizzing)
/**
* 引入类的时候调用
*/
+ (void)load{
}
/**
* 调用类的方法之前调用
*/
+(void)initialize{
//获得类的实例方法
Method originalMethod = class_getInstanceMethod([self class], @selector(viewWillAppear:));
if (!originalMethod) {
return;
}
Method swiMethod = class_getInstanceMethod([self class], @selector(customViewwillAppear:));
if (!swiMethod) {
return;
}
//交换方法
method_exchangeImplementations(originalMethod, swiMethod);
}
/**
* 1: customViewWillApear
2:ViewwillApear
*
* 换成
2: customViewWillApear
1:ViewwillApear
*/
# warning 调用的是ViewWIllApear
- (void)customViewwillAppear:(BOOL)animated{
static int count = 0;
count++;
NSLog(@"ViewwillAppear:%d",count);
[self customViewwillAppear:animated];
}
//调用类的方法之前调用
+(void)initialize{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//获得类的实例方法
Method originalMethod = class_getInstanceMethod([self class], @selector(viewWillAppear:));
if (!originalMethod) {
return;
}
Method swiMethod = class_getInstanceMethod([self class], @selector(customViewWillAppear:));
if (!swiMethod) {
return;
}
//交换方法
method_exchangeImplementations(originalMethod, swiMethod);
});
}
- (void)customViewWillAppear:(BOOL)animated{
static int count = 0;
count ++;
NSLog(@"viewWillAppear:%d",count);
#warning 调用的是viewWillAppear:
[self customViewWillAppear:animated];
}
#import "NSObject+Value.h"
#import <objc/message.h>
@implementation NSObject (Value)
- (void)setValues:(NSDictionary *)values
{
Class c = [self class];
while (c) {
// 1.获得所有的成员变量
unsigned int outCount = 0;
Ivar *ivars = class_copyIvarList(c, &outCount);
for (int i = 0; i<outCount; i++) {
Ivar ivar = ivars[i];
// 2.属性名
NSMutableString *name = [NSMutableString stringWithUTF8String:ivar_getName(ivar)];
// 删除最前面的_
[name replaceCharactersInRange:NSMakeRange(0, 1) withString:@""];
// 3.取出属性值
NSString *key = name;
//得到字典对应key的value值
id value = values[key];
if (!value) continue;
// 4.SEL
// 首字母
NSString *cap = [name substringToIndex:1];
// 变大写
cap = cap.uppercaseString;
// 将大写字母调换掉原首字母
[name replaceCharactersInRange:NSMakeRange(0, 1) withString:cap];
// 拼接set
[name insertString:@"set" atIndex:0];
// 拼接冒号:
[name appendString:@":"];
SEL selector = NSSelectorFromString(name);
// 5.属性类型
NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
#warning ios8不能使用:build settings -> enable strict checking of objc_mssend 改为No
if ([type hasPrefix:@"@"]) { // 对象类型
// objc_msgSend(self, selector, value);
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, selector, value);
} else { // 非对象类型
if ([type isEqualToString:@"d"]) {
objc_msgSend(self, selector, [value doubleValue]);
} else if ([type isEqualToString:@"f"]) {
objc_msgSend(self, selector, [value floatValue]);
} else if ([type isEqualToString:@"i"]) {
objc_msgSend(self, selector, [value intValue]);
} else {
objc_msgSend(self, selector, [value longLongValue]);
}
}
}
c = class_getSuperclass(c);
}
}
@end
在objc_msgSend函数中。首先通过obj的isa指针找到obj对应的class。在Class中先去cache中 通过SEL查找对应函数method(猜测cache中method列表是以SEL为key通过hash表来存储的,这样能提高函数查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,则取superClass中查找。若能找到,则将method加 入到cache中,以方便下次查找,并通过method中的函数指针跳转到对应的函数中去执行。因为C语言的执行顺序是从上到下,举例,就像一个button 在OC中需要点击才会调用里面的方法,而C语言是先访问一次,有时候点击Button会直接出现崩溃,但是在C语言中,直接就没办法执行。
相关函数:
- objc_msgSend : 给对象发送消息
- class_copyMethodList : 遍历某个类所有的方法
- class_copyIvarList : 遍历某个类所有的成员变量
上面的函数都是经常被调用的。