ios runtime 汇总

来源:互联网 发布:linux mmap 实例 编辑:程序博客网 时间:2024/06/05 19:48

本篇文章将一些runtime函数进行一下汇总说明:

      • 一iOS消息机制
      • 二函数交换 method_exchangeImplementations
      • 三添加函数 class_addMethod
      • 四获取属性及成员变量
      • 五归档

一、iOS消息机制

//iOS内部都是通过消息机制实现各个功能的//最好的体现就是通过指令`clang -rewrite-objc`实现objc到c++的转换,然后就可以看到里面的代码:int main(int argc, char * argv[]) {    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;         Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));        return UIApplicationMain(argc, argv, __null, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))));    }}//runtime - c++- (void)runtime_clangCode {    Person *p = objc_msgSend(objc_getClass("Person"), sel_registerName("alloc"));    p = objc_msgSend(p, sel_registerName("init"));    objc_msgSend(p, @selector(eat));}//上面代码等同于    Person *p = [[Person alloc]init];`

二、函数交换 < method_exchangeImplementations >

Method Swizzing是发生在运行时的,主要用于在运行时将两个Method进行交换,我们可以将Method Swizzling代码写到任何地方,但是只有在这段Method Swilzzling代码执行完毕之后互换才起作用。

我们应该在那个地方实现函数的IMP交换呢?

没错,load函数,它是先于
main函数执行的,因此在这里执行可以确保函数在调用之前,函数的实现部分已经完成交换;

如下:
+ (void)load {
Method methodOld = class_getClassMethod([self class], @selector(URLWithString:));
Method methodNew = class_getClassMethod([self class], @selector(hook_URLWithString:));
method_exchangeImplementations(methodOld, methodNew);
}

对于NSArray、NSMutableArray、NSDictionary、NSMutableDictionary又不一样,具体见图:

这里写图片描述

三、添加函数 < class_addMethod >

当我们调用一个不存在的函数式就会报异常,这时我们可以通过添加一个错误处理函数来进行处理:

//解决类方法+ (BOOL)resolveClassMethod:(SEL)sel {    class_addMethod([self class], sel, (IMP)haha, "V:@");    return [super resolveClassMethod:sel];}//解决实例方法+ (BOOL)resolveInstanceMethod:(SEL)sel {    class_addMethod([self class], sel, (IMP)haha, "V:@");    return [super resolveInstanceMethod:sel];}void haha () {    NSLog(@"访问了一个不存在的函数!");}

四、获取属性及成员变量

//获取成员变量    unsigned int count;    Ivar *ivars = class_copyIvarList([self class], &count);    for (int i = 0; i < count; i++) {        Ivar ivar = ivars[i];        const char *keyChar = ivar_getName(ivar);        const char *type = ivar_getTypeEncoding(ivar);        NSLog(@"type :%s",type);        NSString *key = [NSString stringWithCString:keyChar encoding:NSUTF8StringEncoding];        id value = [self valueForKey:key];//获取属性    unsigned int count;    objc_property_t *props = class_copyPropertyList([self class], &count);    for (int i = 0; i < count; i++) {        objc_property_t prop = props[i];        const char *proChar = property_getName(prop);        NSString *key = [NSString stringWithCString:proChar encoding:NSUTF8StringEncoding];        id value = [self valueForKey:key];    }

五、归档

普通数据可以进行归档处理,如果一个对象需要实现NSCoding协议才可以进行归档操作;
下面说一个简单的归档(假设我们有一个Person类)

//1、实现NSCoding协议#import "Person.h"#import <objc/message.h>@interface Person()<NSCoding>@end@implementation Person- (instancetype)initWithCoder:(NSCoder *)aDecoder {    self = [super init];    if (self) {        unsigned int count;        Ivar *ivars = class_copyIvarList([self class], &count);        for (int i = 0; i < count; i++) {            Ivar ivar = ivars[i];            const char *keyChar = ivar_getName(ivar);            const char *type = ivar_getTypeEncoding(ivar);            NSLog(@"type :%s",type);            NSString *key = [NSString stringWithCString:keyChar encoding:NSUTF8StringEncoding];            id value = [aDecoder decodeObjectForKey:key];            [self setValue:value forKey:key];        }        free(ivars);    }    return self;}- (void)encodeWithCoder:(NSCoder *)aCoder {    unsigned int count;    Ivar *ivars = class_copyIvarList([self class], &count);    for (int i = 0; i < count; i++) {        Ivar ivar = ivars[i];        const char *keyChar = ivar_getName(ivar);        const char *type = ivar_getTypeEncoding(ivar);        NSLog(@"type :%s",type);        NSString *key = [NSString stringWithCString:keyChar encoding:NSUTF8StringEncoding];        id value = [self valueForKey:key];        [aCoder encodeObject:value forKey:key];    }    free(ivars);}@end//2、设置一个归档路径//获取归档路径- (NSString *)path {    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];    path = [path stringByAppendingPathComponent:@"p.arc"];    return path;}//3、归档实现//遍历属性、归档- (void)runtime_archive {    Person *p = [[Person alloc]init];    p.name = @"li";    p.age = 18;    [NSKeyedArchiver archiveRootObject:_p toFile:[self path]];}//4、解归档- (void)runtime_unArchive {    Person *p = [NSKeyedUnarchiver unarchiveObjectWithFile:[self path]];    NSLog(@"person--:%@",p);}
原创粉丝点击