移动端开发

Runtime 运行时(未完待续)

2016-09-23  本文已影响9人  码路芽子

Runtime简介

Runtime各种方法使用

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);

开发中使用场景

二 交换方法

案例

/** 把类记载进内存的时候只调用一次 */
+ (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"]; 
}

三 动态添加方法

*/

在类中添加一个方法


/** 没有返回值没有参数 */
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];
}

上一篇下一篇

猜你喜欢

热点阅读