前言  

  上一篇中我们大致的了解了runtime的一些基本概念,这一篇我们一起来看看如何使用它。

3、如何使用runtime。

3.1 方法交换  

  举一个老生常谈的例子。当你接手一个新的项目,需要查看这个程序运行时出现的UI对应的控制器的时候,如果你单纯的去通过UI上面的关键词全局搜索或是在viewwillappear里面打印该类的类名,你会浪费很长的时间,而且你会很难受。这个时候用runtime就会很好处理这种情况。

  UI出现的时候,都会调用方法viewWillAppear。也就是说,如果我能让程序统一不走这个方法,走另一个方法(假设名字是myViewWillAppear),而这个方法内部还是会调用viewWillAppear,那么我就可以在myViewWillAppear中打印将要出现的UI的类名。看看下面的代码:

#import "UIViewController+WillAppear.h"
#import <objc/runtime.h> @implementation UIViewController (WillAppear)
+ (void)load{
Method method1 = class_getInstanceMethod([self class], @selector(viewWillAppear:));
Method method2 = class_getInstanceMethod([self class], @selector(logViewWillAppear:));
method_exchangeImplementations(method1, method2);
} - (void)logViewWillAppear:(BOOL)animated{
NSString *className = NSStringFromClass([self class]);
if ([className hasPrefix:@"LMF"]) {
NSLog(@"%@ will appear", className);
}
[self logViewWillAppear:animated];
}
@end

  将系统的viewwillappear的指针与logviewwillappear的指针交换,这样,UI出现的时候会先调用logviewwillappear然后再调用viewwillappear方法,目的便达到了。

  以此类推,我们有时会碰到unrecognized selector这种错误,这种错误很低级,但确实存在。对于初级开发者来讲时常会碰到,这个时候如果用runtime检测对象是否实现了此方法判断是否需要将该方法替换成其他事先已经实现的方法,可以避免这种错误。不过,推荐别这样玩,因为bug暴露越早越好,这里只是谈一下runtime解决这种问题的可行性。

3.2 可拓展性(动态添加方法和属性)

  讲道理,我们还是要遵守一下可拓展性的。谁都不希望接手一份处处都要修改源码的代码,这个时候如果拓展性高,在不改变类内部源码的情况下给这个类添加额外的方法或者属性无疑是最好的。正好,oc的runtime很好的提供了这种特性。

  其实我们一直都在用runtime,category就是最好的证明。它可以帮助我们给某些类在不需要修改该类内部的源码的情况下添加额外的方法,我们形象的称之为类别。类别怎么写我就不说了,你不会写算我输。添加方法用类别,那么添加属性能不能用类别呢?非常遗憾,oc没有这种语法。这个时候,还是用到runtime,看看下面代码,就懂了怎么添加:

objc_setAssociatedObject([UIApplication sharedApplication].delegate, @"USEROperationUnReadCount", [NSNumber numberWithInteger:count], OBJC_ASSOCIATION_RETAIN);

objc_getAssociatedObject([UIApplication sharedApplication].delegate, @"USEROperationUnReadCount");

  上述代码是给AppDelegate动态添加了一个属性叫USEROperationUnReadCount,值是个NSNumber对象,OBJC_ASSOCIATION_RETAIN表示这个属性的内存管理模式。get方法是将这个新加的属性值取出来,这样形成一个完整的结构。

  通过类别动态的添加方法是非常方便的,这里还说一种比较不常用的方式,不推荐使用。话不多说,直接上代码。

  .m中代码:

#import "LMFView.h"
#import <objc/runtime.h>
void show(id self, SEL _cmd, NSString *message){
NSLog(@"%@", message);
}
void eat(id self, SEL _cmd, NSString *who){
NSLog(@"%@ eat meat", who);
}
@implementation LMFView + (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(show)) {
class_addMethod([self class], sel, (IMP)show, "v@:@:");
return YES;
}else if (sel == @selector(eat)) {
class_addMethod([self class], sel, (IMP)eat, "v@:@:");
return YES;
}
return [super resolveInstanceMethod:sel];
} @end

  .h中代码:

#import <UIKit/UIKit.h>

@interface LMFView : UIView

@end

  我们可以看到,并没有声明方法eat。然后我们在外部调用eat,当然不能直接通过[]调用,因为编译通不过。用选择器调用:

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
self.lmfView = [[LMFView alloc] initWithFrame:CGRectMake(, , , )];
self.lmfView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.lmfView]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showNextView)];
[self.lmfView addGestureRecognizer:tap]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(, , , );
button.backgroundColor = [UIColor cyanColor];
[button setTitle:@"runtime" forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button addTarget:self action:@selector(show) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
} - (void)show
{
[self.lmfView performSelector:@selector(eat) withObject:@"

runtime(二)的更多相关文章

  1. <runtime> 的 <assemblyBinding> 元素

    一.<assemblyBinding> 元素 包含有关程序集版本重定向和程序集位置的信息. <assemblyBinding xmlns="urn:schemas-micr ...

  2. HeadFirst设计模式之装饰者模式

    一. 1.The Decorator Pattern attaches additional responsibilities to an object dynamically.Decorators ...

  3. [转] 使用maven运行java main的三种方式

    原文地址: http://blog.csdn.net/qbg19881206/article/details/19850857?utm_source=tuicool&utm_medium=re ...

  4. 自定义xUtils框架

    xUtils是基于Afinal开发的目前功能比较完善的一个Android开源框架,最近又发布了xUtil3.0,在增加新功能的同时又提高了框架的性能.它的功能很强大,但是有时候我们只需要其中的一些功能 ...

  5. .NetCore程序发布到IIS上面

    一.概述 在传统的.NET Framework中,ASP.NET程序发布到IIS上面,是由IIS的工作进程(w3wp.exe)托管的,在任务管理器中可以找到该进程.在ASP.NET Core程序中不再 ...

  6. Thinkphp5笔记五:配置data文件夹

    如果你看项目下的各种文件,有种乱七八糟的感觉的话,你就可以进行以下配置. 配置data文件夹的,整理各种文件,让看起来舒服些. 一.设置runtime文件夹 index.php define('RUN ...

  7. signalR常见问题

    一.安装signalR会对应安装自己的NewJson包,如果引用了含有不同NewJson包的dll组件,会造成版本不一致.必须在运行环境中指出使用目标版本. 问题截图: 解决方式: <runti ...

  8. Maven学习总结(五):maven命令的含义及用法

    Maven有许多命令,不管是在命令行(1),还是在Myecplise10的Maven项目--右键Run As(2),还是IDEA的左下角--Maven Projects--Maven项目名--Life ...

  9. 使用Maven运行Java main的3种方式使用Maven运行Java main的3种方式

    maven使用exec插件运行java main方法,以下是3种不同的操作方式. 一.从命令行运行 1.运行前先编译代码,exec:java不会自动编译代码,你需要手动执行mvn compile来完成 ...

随机推荐

  1. OpenGL数据类型及相应C数据类型

  2. JQuery EasyUI datagrid pageNumber 分页 请求/加载 两次

    解决方案: 原因是 jquery.easyui.min.js 源文件中,由于第1页的total和其他页的total不相等,EasyUI会重新发起第1页的请求!1.jQuery EasyUI 1.4.1 ...

  3. poj3020 Antenna Placement 匈牙利算法求最小覆盖=最大匹配数(自身对应自身情况下要对半) 小圈圈圈点

    /** 题目:poj3020 Antenna Placement 链接:http://poj.org/problem?id=3020 题意: 给一个由'*'或者'o'组成的n*m大小的图,你可以用一个 ...

  4. vue使用axios请求本地json文件出现404

    之前的路径是这么写的,一直出现404,后来发现必须是http的才可以,这样是无法请求的 把路径改为以下   位置根据json文件决定,但是必须是http://localhost:断口号

  5. CI框架整合微信公共平台接口

    #CI框架控制器 <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); /*** CI框架整合微信 ...

  6. 一句话搞定IOS中View的Frame和Bound

    就一句话,Frame是父View上看到子View的窗户,Bound是子View上可以被父View看见的内容. 稍微解释下.Frame 指子View在父View中的位置以及大小.由两部分构成,第一部分是 ...

  7. Django - 安装wagtail

    感觉这个CMS系统不错,试用了一下,记录过程: 1. 安装Virtualenv mkdir wagtail virtualenv --no-site-packages --python=3.5 wag ...

  8. 第二百三十三节,Bootstrap表格和按钮

    Bootstrap表格和按钮 学习要点: 1.表格 2.按钮 本节课我们主要学习一下 Bootstrap 表格和按钮功能,通过内置的 CSS 定义,显示各 种丰富的效果. 一.表格 Bootstrap ...

  9. 第一百三十七节,JavaScript,封装库---修缮拖拽

    JavaScript,封装库---修缮拖拽 修缮拖拽 /** tuo_zhuai()方法,将一个弹窗元素实现拖拽功能 * 注意:有参设置拖拽点区块,只有弹窗的这个拖拽点区块才能拖拽,无参整个弹窗可以拖 ...

  10. 列出自己常用的jdk包.

    解答:JDK常用的package java.lang: 这个是系统的基础类,比如String等都是这里面的,这个package是唯一一个可以不用import就可以使用的Package java.io: ...