OC runtime

1.程序是怎样运行起来的?(以C语言以及VC运行环境为例)
  1. 编辑
  • (把程序代码输入,交给计算机)。
  1. 编译(成目标程序文件.obj)
  • 编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序把人们熟悉的语言换成2进制的。
  • 编译程序把一个源程序翻译成目标程序的工作过程分为五个阶段:词法分析;语法分析;语义检查和中间代码生成;代码优化;目标代码生成。主要是进行词法分析和语法分析,又称为源程序分析,分析过程中发现有语法错误,给出提示信息。
  1. 链接(成可执行程序文件.exe)。
  • 链接是将编译产生的.obj文件和系统库连接装配成一个可以执行的程序。
  • 为何要将源程序翻译成可执行文件的过程分为编译和链接两个独立的步骤,不是多此一举吗?之所以这样做,主要是因为:在一个较大的复杂项目中,有很多人共同完成一个项目(每个人可能承担其中一部分模块),其中有的模块可能是用汇编语言写的,有的模块可能是用VC写的,有的模块可能是用VB写的,有的模块可能是购买(不是源程序模块而是目标代码)或已有的标准库模块,因此,各类源程序都需要先各自编译成目标程序文件(2进行机器指令代码),再通过链接程序将这些目标程序文件连接装配成可执行文件。
  1. 运行(可执行程序文件)。
  • 上述四个步骤中,其中第一步的编辑工作是最繁杂而又必须细致地由人工在计算机上来完成,其余几个步骤则相对简单,基本上由计算机来自动完成。
2. 动态语言和静态语言的在程序不同阶段是怎样处理的?

编程语言有静态和动态之分。

静态语言就是,在程序运行前决定了所有的类型判断,类的所有成员,方法在编译阶段就确定好了内存地址,也就意味着所有的类对象只能访问属于自己的成员变量和方法,否则编译器直接报错。如:java,C++,C

动态语言,类型的判断、类的成员变量、方法的内存地址都是在程序的运行阶段才最终确定,并且还能动态的添加成员变量和方法。也就意味着你调用一个不存在的方法时,编译也能通过,甚至一个对象它是什么类型并不是表面我们所看到的那样,只有运行之后才能决定其真正的类型。相比于静态语言,动态语言具有较高的灵活性和可订阅性。而OC,正是一门动态语言。

3. runtime
运行时:

就是程序在运行时做的一些事。

runtime :

runtime 是OC底层的一套C语言的API,它是一个C和汇编写的动态库,将OC和C紧密关联。编译器最终都会将OC代码转化为运行时代码。

runtime这个系统主要做两件事 :

1、封装C语言的结构体和函数,让开发者在运行时创建、检查或者修改类、对象和方法等等。
2、传递消息,找出方法的最终执行代码。

在OC中,如果想要某个对象传递消息,那么就会使用动态绑定机制来决定需要调用的方法。在底层,所有的方法都是普通的C语言函数,然而对象收到消息之后,究竟该调用哪个方法则完全取决于运行期决定,甚至在运行时改变,这些特性使得OC成为一门真正的动态的语言。

OC中的重要工作都由“运行期组件”而不是编译器来完成,使用OC面向对象特性所需的全部数据结构及函数都在运行期组件里面。例如:运行期组件中含有全部的内存管理的方法。

在提高性能的方面:只需要更新运行期组件,即可提升应用程序的性能。而在那种许多的工作都在编译期完成的语言,若想要获得类似的性能提升,则要重新编译应用程序代码。

4.要了解运行时,我们得先了解OC的消息机制
4.1 消息发送(Messaging):是 Runtime 通过 selector(选择子) 快速查找 IMP 的过程,有了函数指针就可以执行对应的方法实现;

id returnValue = [someObject messageName: parameter];

调用的runtime函数:
原型:void objc_msgSend(id self, SEL cmd, . . . )
id returnValue = objc_msgSend(someObject,@ selector(messageName:), parameter);

解释:objc_msgSend函数会根据接受者和选择子的类型来调用适当的方法。为了接收完成这个操作,该方法需要在接收者(someObject)所属的类中搜寻其“方法列表”,如果能找到就跳转到实现代码,若不能,就沿着继承体系向上查找,找到后在跳转,如果最终都找不到,就执行“消息转发”。

4.2 消息转发(Message Forwarding):是在查找 IMP 失败后执行一系列转发流程的慢速通道,如果不作转发处理,则会打日志和抛出异常。

当对象接受到无法解读的消息的时候,就会启动“消息转发”机制,程序员可以经由此过程告诉对象该如何处理这个消息。

消息转发分为2大阶段:

  • 第一阶段先征询接受者,所属的类,看是否能动态的添加方法,以处理当前这个“未知的选择子”,这叫做动态方法解析。
  • 第二阶段涉及“完整的消息转发机制”,当运行期系统已经将第一阶段执行完了,那么系统会请求接受者以其他的手段来处理与消息相关的方法调用。1.请接收者看看有没有备援的接受者可以处理这个消息,若有,消息转发结束,若还是没有就启动完整的消息转发机制,运行期系统会把与消息有关的全部信息封装到NSInvocation对象中去,在给接受者最后一次机会,令其设法解决当前未处理的这条信息。


    屏幕快照 2017-12-12 15.39.00.png
5.runtime的主要应用

(1)替换系统方法

#import "UIImage+ImageLoad.h"
#import <objc/runtime.h>
@implementation UIImage (ImageLoad)

//自定义方法中最后一定要再调用一下系统的方法,让其有加载图片的功能,但是由于方法交换,系统的方法名已经变成了我们自定义的方法名,这就实现了系统方法的拦截!
+(UIImage *)xh_imageNamed:(NSString *)name {
    double version = [[UIDevice currentDevice].systemVersion doubleValue];
    if (version >= 7.0) {
        name = [name stringByAppendingString:@"_ios7"];
    }
    return [UIImage xh_imageNamed:name];
    
}


//分类中重写UIImage的load方法,实现方法的交换,
+(void)load {
    //获取2个类的方法
    Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
    Method m2 = class_getClassMethod([UIImage class], @selector(xh_imageNamed:));
    
    //交换
    method_exchangeImplementations(m1, m2);
}

@end

(2)实现分类关联属性

#import "UIButton+BtnImageView.h"
#import <objc/runtime.h>

@implementation UIButton (BtnImageView)

-(UIImageView *)btnImageView
{
    // return objc_getAssociatedObject(self, @selector(isClicked));
    return objc_getAssociatedObject(self, &kbtnImageView);
}

//set
static char kbtnImageView;
-(void)setBtnImageView:(UIImageView *)btnImageView
{
    //如果是指针类型
    return objc_setAssociatedObject(self, &kbtnImageView, btnImageView, OBJC_ASSOCIATION_RETAIN);
    
    //1 源对象self
    //2 关键字 唯一静态变量key isClicked
    //3 关联的对象
    //4 关键策略  OBJC_ASSOCIATION_RETAIN_NONATOMIC
    //objc_setAssociatedObject(self, @selector(isClicked), @(isClicked), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
}
@end

(3)字典转model

(4)归档

(5) 万能控制器跳转

- (void)push:(NSDictionary *)params
{
    // 类名
    NSString *class =[NSString stringWithFormat:@"%@", params[@"class"]];
    const char *className = [class cStringUsingEncoding:NSASCIIStringEncoding];
    // 从一个字串返回一个类
    Class newClass = objc_getClass(className);
    if (!newClass)
    {
        // 创建一个类
        Class superClass = [NSObject class];
        newClass = objc_allocateClassPair(superClass, className, 0);
        // 注册你创建的这个类
        objc_registerClassPair(newClass);
    }
    // 创建对象
    id instance = [[newClass alloc] init];
    // 对该对象赋值属性
    NSDictionary * propertys = params[@"property"];
    [propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        // 检测这个对象是否存在该属性
        if ([self checkIsExistPropertyWithInstance:instance verifyPropertyName:key]) {
            // 利用kvc赋值
            [instance setValue:obj forKey:key];
        }
    }];
    // 获取导航控制器
    UITabBarController *tabVC = (UITabBarController *)self.window.rootViewController;
    UINavigationController *pushClassStance = (UINavigationController *)tabVC.viewControllers[tabVC.selectedIndex];
    // 跳转到对应的控制器
    [pushClassStance pushViewController:instance animated:YES];
}

//检测是否存在这个属性

- (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName
{
    unsigned int outCount, i;
    // 获取对象里的属性列表
    objc_property_t * properties = class_copyPropertyList([instance
                                                           class], &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property =properties[i];
        //  属性名转成字符串
        NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        // 判断该属性是否存在
        if ([propertyName isEqualToString:verifyPropertyName]) {
            free(properties);
            return YES;
        }
    }
    free(properties);
    return NO;
}

(7)插件开发

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容