Runtime 运行时(未完待续)

Runtime简介

  • Runtime简称运行时. OC就是运行时机制, 也就是在运行的时候的一些机制, 其中最主要的是消息机制
  • 对于C语言, 函数的调用在编译的时候会决定调用哪个函数
  • 对于OC的函数, 属于动态调用过程, 在编译的时候并不能决定真正调用哪个函数, 只有在真正运行的时候才会根据函数的名字来调用
  • 事实证明
    • 在编译阶段, OC可以调用任何函数, 即使这个函数并未实现, 只要声明过就不会报错
    • 在编译阶段, C语言调用未实现的函数就会报错

Runtime各种方法使用

Runtime消息机制

  • 介绍
  • 方法调用本质: 就是发送一个消息, 用Runtime发送消息, OC底层是通过Runtime实现

    导入头文件 `#import <objc/message.h>`

    id objc = [NSObject alloc];
    objc = [objc init];
    /**
     * 最终生成消息机制, 编辑器做的事情
     * 最终代码, 需要把当前代码重新编译, 用xcode编译器, clang
     * clang -rewrite-objc main.m 查看最终生成代码
     * Runtime都有个前缀, 谁的事情就使用谁
     */
     /**
     * id: 谁发送消息
     * SEL: 发送什么消息
     */

    
    /**
     * xcode6之前, 苹果可以使用objc_msgSend, 而且有参数提示
     * xcode6之后不推荐使用Runtime
     * 解决方法: 找到build setting -> 搜索msg, 改成NO, 不用严格检查
            这样Runtime就正常了
     */
    
    /**
     * id objc = [NSObject alloc];
     * objc = [objc init];.
     
     * 用Runtime写这两句
       *太麻烦 id objc = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)([NSObject class], @selector(alloc));
     */
     id objc = objc_msgSend([NSObject class], @selector(alloc));
    objc = objc_msgSend(objc, @selector(init));
    
    
    ******************
    //TODO: 什么时候调用Runtime, 方法调用流程
    /** 最底层写法 */
    Person *per = [Person alloc];
    objc_msgSend(objc_getClass("Person"), sel_registerName("alloc"));
    per = [per init];
    objc_msgSend(per, sel_registerName("init"));

    /** 调用对象方法 */
    objc_msgSend(per, @selector(eat));

什么时候使用runtime

不得不用runtime消息机制, 可以调用私有方法, 因为正常的没有声明的方法, oc不能使用

//TODO: 什么时候调用Runtime, 方法调用流程
    /** 最底层写法 */
    Person *per = [Person alloc];
    objc_msgSend(objc_getClass("Person"), sel_registerName("alloc"));
    per = [per init];
    objc_msgSend(per, sel_registerName("init"));
  
    /** 调用对象方法 */
    objc_msgSend(per, @selector(eat));
    objc_msgSend(per, @selector(run:), 20);

开发中使用场景

  • Runtime的方法都是有前缀的, 谁的事情谁开头

  • 方法调用流程

  • 怎么去调用eat方法, 对象方法: 类对象的方法列表中 类方法: 元类中方法列表

  • 1.通过isa去对应的类中查找方法


    QQ20160923-0.png

    2.注册方法编号
    3.根据方法编号去查找对应方法
    4.找到的只是最终函数实现地址, 根据地址去方法区调用对应函数

  • 内存的5大区

    1. 栈区 -> 不需要手动管理内存, 自动管理
    2. 堆 -> 需要手动管理内存, 根据地址去方法去调用
    3. 静态区
    4. 常量区
    5. 方法区

二 交换方法

案例

/** 把类记载进内存的时候只调用一次 */
+ (void)load
{
    /** 获取方法
       * imageNamed
       * wdy_imageNamed
     */
    /** 获取那个类方法, 获取那个方法 */
    Method imageNamedMethod = class_getInstanceMethod(self, @selector(imageNamed:));
    Method wdy_imagenameMethod = class_getInstanceMethod(self, @selector(wdy_imageNamed:));
    
    /** Runtime交换方法 */
    method_exchangeImplementations(imageNamedMethod, wdy_imagenameMethod);
    
}

/** 调用多次  */
+ (void)initialize
{
    
}

/** 加载图片 */
/** 判断是否加载成功 */
+ (UIImage *)wdy_imageNamed:(NSString *)name
{
    UIImage *image = [self wdy_imageNamed:name];
    if (image) {
        NSLog(@"加载成功");
    } else {
        NSLog(@"加载失败");
    }
    return image;
}
/**
 * Runtime(交换方法):
 * 需求:让UIImage加载图片, 告诉我是否成功
    解决方法: 
    1.自定义UIimage
        弊端:
        *.每次使用, 都需要导入
        *.项目大了, 没办法实现
    2.用UIimage方法
        给系统imageNamed添加功能, 只能用Runtime
 
    解决方法: 
        1.给系统添加方法分类
        2.自己实现一个带有扩展功能的方法
        3.交换方法, 只需要交换一次    
 *
 */


@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    /** 麻烦的方法 */
    UIImage *image = [UIImage imageNamed:@"1.png"]; 
}

三 动态添加方法

  • 描述: 添加一个类, 想要在适当的时候添加一个方法, 例如当用户成为会员的时候, 进行一些操作
  • 问题: Runtime动态添加方法:OC中都是懒加载机制, 只要有个方法实现了, 就立马添加到方法列表中
    美团有个面试题 有没有使用过 self performSelector:<#(SEL)#>, 什么时候使用?动态添加方法的时候使用过.
    怎么动态添加方法?用Runtime添加. 为什么要动态添加?

*/

  • 准备: 在ViewDidLoad中创建一个类, 并且添加一个方法

      - (void)viewDidLoad {
        [super viewDidLoad];
         
        Person *per = [[Person alloc] init];
        [per performSelector:@selector(eat)];
    
        [per performSelector:@selector(run:) withObject:@10];
    }
    
    

在类中添加一个方法

  • 这个方法在一个地方调用了未实现的方法就会调用: + (BOOL)resolveInstanceMethod:(SEL)sel

/** 没有返回值没有参数 */
void aaa(id self, SEL _cmd) {
   NSLog(@"吃东西啊啊 啊啊啊啊!");
}

void run(id self, SEL _cmd, NSNumber *num) {
   NSLog(@"跑了%@", num);
}


/**
* 解决添加的方法
* 什么时候调用方法: 只要一个对象调用了一个未实现的方法就会调用这个方法, 进行处理 
* 作用: 动态添加方法, 处理未实现
*/
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
   /** 任何方法都有两个隐士:sel, cmd->方法编号 */
   if (sel == NSSelectorFromString(@"eat")) {
       /**
        * 给谁添加方法
        * SEL: 添加那个方法
        * IMP: 方法实现
        * type: 方法类型
        */
       class_addMethod(self, sel, (IMP)aaa, "v@:");
   }
   
   if (sel == NSSelectorFromString(@"run:")) {
       class_addMethod(self, sel, (IMP)run, "v@:@");
   }

 return [super resolveInstanceMethod:sel];
}

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

推荐阅读更多精彩内容

  • 对于从事 iOS 开发人员来说,所有的人都会答出【runtime 是运行时】什么情况下用runtime?大部分人能...
    梦夜繁星阅读 3,697评论 7 64
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,678评论 0 9
  • 本文分为4个部分 1.介绍OC和C语言之间的转换 2.介绍运行时和相关术语 3.介绍消息发送机制已及怎样找到函数实...
    一片枫叶随风舞阅读 302评论 0 1
  • 参考链接: http://www.cnblogs.com/ioshe/p/5489086.html 简介 Runt...
    乐乐的简书阅读 2,129评论 0 9
  • 书房里很安静,摆设也是极简单,只有一套老式书桌跟柜子。吴忧坐在书桌前心里有些烦躁,这个月截稿日期只剩下一周,自己...
    无忧L阅读 1,040评论 0 1