前言  

  上一篇中我们大致的了解了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. EF(EntityFramework) Migrations 迁移

    1.开启程序包管理器控制台 2.安装EntityFramework PM> Install-Package EntityFramework   3.启用迁移 PM> Enable-Migr ...

  2. erlang supervisor中启动普通的进程

    文字部分转自: http://1234n.com/?post/qou3eb supervisor的子进程 一开始使用supervisor的时候,我用的是init/1返回子进程规格列表的方式,并且所有子 ...

  3. iOS音频合并

    iOS音频合并 最近遇到一个需求,客户录音试听一下可以,就继续向下录制,当客户录制完成后,需要把前面录制的试听音频和后面的音频进行合并.最初想到的方法,使用NSData对两个音频文件进行合并,但是合并 ...

  4. 谈一谈APP支付失败的处理

    如题今天要描述一个问题是:程序在确认订单时拉起第三方支付,支付失败了,引起的问题. 为了能清楚的描述问题,我把场景复现一下,大家肯定都有过APP购物的体会,大家一定知道有一个按钮叫“确认”或者“结算” ...

  5. SAML2.0 协议初识(三)——IDP

    IDP,即提供身份认证服务的一端,通常,当 IDP 接收到 SP 发送的 SAML 认证请求后,解析 SAMLRequest 参数,包括 acs 地址.SP EntityId.绑定方式.是否加密等信息 ...

  6. 基于ZK的分布式锁实现

    import java.util.concurrent.TimeUnit; import org.apache.curator.framework.CuratorFramework; import o ...

  7. mysql 分数表实现排名

    首先初始化一张表 DROP TABLE IF EXISTS `lq_wx_sign`; CREATE TABLE `lq_wx_sign` ( `id` ) unsigned NOT NULL AUT ...

  8. 2017 ACM区域赛(西安) 参赛流水账

    day 0: 周五, 鸽了概统课,早上和紫金港的几位小伙伴一起打车去萧山机场,从咸阳机场到西北工业大学坐了五十多个站的公交车,感觉身体被掏空.晚上在宾馆本来打算补之前训练的一个题,想想还是先花个十来分 ...

  9. 【vijos】1750 建房子(线段树套线段树+前缀和)

    https://vijos.org/p/1750 是不是我想复杂了.... 自己yy了个二维线段树,然后愉快的敲打. 但是wa了两法.......sad 原因是在处理第二维的更新出现了个小问题,sad ...

  10. Objective-C中的instancetype和id关键字(转)

    转自:Objective-C中的instancetype和id关键字 一.什么是instancetype 同id一样,都是表示未知类型的的对象. 二.关联返回类型(related result typ ...