iOS RunTime的简单使用
1.根据指定规则根据runtime进行页面选择跳转
背景:要根据后台返回的数据 进行选择要跳转到哪一个ViewController
// 这个规则肯定事先跟服务端沟通好,跳转对应的界面需要对应的参数
NSDictionary *userInfo = @{
@"class": @"HSFeedsViewController",
@"property": @{//类中所需要的参数
@"ID": @"123",
@"type": @"12"
}
};
思路:使用runtime去解决这个问题的思路就是 通过运行时 根据对应的类名去创建类以及类的属性,这就需要和服务端去协商返回的数据形式 要类似:
实现: 这里使用了三个objc/runtime.h中函数分别是:
- (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, );
// 注册你创建的这个类
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];
}
(1)objc_getClass(const char *name) 即返回对应的类;
(2)objc_allocateClassPair(Class superClass,const char*name ,size_t extraBytes) 为对应的类设置父类,并根据父类和extraBytes(变量的字节数) 给这个类分配空间
(3)objc_registerClassPair(class) 注册这个类
通过这三个函数 创建类一个类
还有一个运行时函数 class_copyPropertyList(Class class,unsigned int *outCount)
/**
* 检测对象是否存在该属性
*/
- (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName
{
unsigned int outCount, i;
// 获取对象里的属性列表
objc_property_t * properties = class_copyPropertyList([instance
class], &outCount);
for (i = ; 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;
}
objc_property_t class_copyPropertyList(Class class,unsigned int *outCount) 返回值为一个数组 数组中为对应的类的属性列表 以此来对比类中是否含有当前属性,从而通过KVC为类的属性赋值.
2.修改系统类的方法实现
背景:如果需求中要统计每个viewController 展示给用户的次数,我们想到的就是在ViewController中添加对应的统计的代码,但是会很麻烦,此时可以创建一个UI ViewController的分类更改底层中viewWillAppear的实现 这就用到runtime中method Swizzling (方法混合)
实现:通过methodSwizzling 修改了UIViewController的@selector(viewWillAppear:)对应的函数指针,使他的实现指向了自定的方法
#import "UIViewController+Tracking.h"
#import <objc/runtime.h>
@implementation UIViewController (Tracking)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzlingSelector = @selector(swizzling__viewWillAppear:);
Method originMethod = class_getInstanceMethod(class, originalSelector);
Method swizzlingMethod = class_getInstanceMethod(class, swizzlingSelector);
//将 swizzlingMethod 中的实现过程添加到 originalSelector 这个方法中
BOOL didAddMethod = class_addMethod(class,originalSelector, method_getImplementation(swizzlingMethod), method_getTypeEncoding(swizzlingMethod));
if (didAddMethod) {
//用 originMethod中的实现 替换 swizzlingSelector这个方法中的实现 这样原始的和自定义的方法都执行的时同一个实现过程
class_replaceMethod(class, swizzlingSelector, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
}else{//可能出现添加失败的情况(比如 被添加的方法中已经存在了对应方法的实现 就会返回NO)
//将 originMethod 和 swizzlingMethod中的实现过程进行交换
method_exchangeImplementations(originMethod, swizzlingMethod);
}
});
}
/*
经过上面的 class_method 和 class_replaceMethod 或 method_exchangeImplementations 就实现了
//http://blog.jobbole.com/79580/
*/
- (void)swizzling__viewWillAppear:(BOOL)animation
{
[self swizzling__viewWillAppear:animation];
NSLog(@"swizzling_viewWillAppear");
}
(1)通过两个方法 class_addMethod class_replaceMethod这个方法实现方法Method这个结构体中 IMP对应的函数指针对应的函数实现进行添加 或者 替换SEL 代表了Method的名称name,IMP代表函数指针 即为函数在内存中的开始位置
另外还有一些注意事项 为什么一定要写在load中 还要写在dispatch_once中,因为swilzzing method会影响代码的整体状态 甚至有可能改变程序的运行流程,要保证避免并发的竞争,而+load方法是在类初始化就进行了加载(这里不太明白具体原理)详细参看下面链接
http://nshipster.com/method-swizzling/
iOS RunTime的简单使用的更多相关文章
- iOS Runtime的消息转发机制
前面我们已经讲解Runtime的基本概念和基本使用,如果大家对Runtime机制不是很了解,可以先看一下以前的博客,会对理解这篇博客有所帮助!!! Runtime基本概念:https://www.cn ...
- iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制
你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...
- ios runtime swizzle
ios runtime swizzle @implementation NSObject(Extension) + (void)swizzleClassMethod:(Class)class orig ...
- ios runtime的相关知识
一.iOS runtime原理 对于runtime机制,在网上找到的资料大概就是怎么去用这些东西,以及查看runtime.h头文件中的实现,当然这确实是一种很好的学习方法,但是,其实我们还是不会知道r ...
- ios下最简单的正则,RegexKitLite
ios下最简单的正则,RegexKitLite 1.去RegexKitLite下载类库,解压出来会有一个例子包及2个文件,其实用到的就这2个文件,添加到工程中.备用地址:http://www.coco ...
- iOS Runtime 实践(1)
很多时候我们都在看iOS开发中的黑魔法——Runtime.懂很多,但如何实践却少有人提及.本文便是iOS Runtime的实践第一篇. WebView 我们这次的实践主题,是使用针对接口编程的方式,借 ...
- iOS中XMPP简单聊天实现 好友和聊天
版权声明本文由陈怀哲首发自简书:http://www.jianshu.com/users/9f2e536b78fd/latest_articles;微信公众号:陈怀哲(chenhuaizhe2016) ...
- 包建强的培训课程(11):iOS Runtime实战
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- iOS Runtime 实操练习
iOS Runtime 知识详解: http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/ 一般可以运行Runtime进行以下操作 ...
随机推荐
- nyoj 16 矩形嵌套
矩形嵌套 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a& ...
- [OC Foundation框架 - 18] Class
使用Class来创建实例 // 18.通过@"Ball"创建一个Ball实例(不可以使用[[Ball alloc] init]创建) NSString *className = @ ...
- Shell 脚本学习资料搜集
Shell文档 ChinaUnix上大神“網中人”总结的Shell十三问,强烈推荐,这本书讲得比较精炼,而且都是一些Shell学习中容易把握不住的一些细节难点.每一问都写得非常精彩.ChinaUnix ...
- C#模仿360安全卫士玻璃按钮,不闪烁,背景切换效率快
首先先上效果图: 1.准备两张透明的png图片(尺寸74 x 82),一张用于鼠标进入控件时显示,一张用于鼠标单击控件时显示 2.拖一个GlassButton按钮 3.设置按钮属性 this.btnE ...
- VirtualBox NAT方式与主机互相通信
之前说过,桥接方式适合在统一的网络环境中使用(一样的网关和许可). 如果网络环境发生改变,那就难堪了 -- 这就是我遇到的问题,公司里每人的IP都是固定的. 解决办法,改为NAT网络地址转换模式. 但 ...
- 可学习的多人人脸识别程序(基于Emgu CV)
源代码下载(需要安装Emgu CV,安装方法请百度) 很多朋友使用Emgu CV遇到CvInvoke()的报错,我找到一种解决方法. 把EmguCV目录下bin里面的所有dll复制到C:\WINDOW ...
- 终端神器 iterm
1.简介 mac自带的终端terminal算蛮好用的, 但相比另一款优秀的终端软件iterm,iterm这款神器不逊于mac自带的终端.它支持了很多快捷键, 深受键盘党的喜爱. 2.下载 http:/ ...
- 关于 mysql.test 数据库
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- 2014 ACM/ICPC 鞍山赛区现场赛 D&I 解题报告
鞍山现场赛结束了呢-- 我们出的是D+E+I三道题-- 吾辈AC掉的是D和I两道,趁着还记得.先在这里写一写我写的两道水题D&I的解题报告吧^_^. D题的意思呢是说星云内有一堆排成一条直线的 ...
- IOS开发-加载本地音乐
IOS开发-加载本地音乐 $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text() ...