ios runtime 汇总

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

一、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);
}
发布了172 篇原创文章 · 获赞 35 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/u012198553/article/details/78743130