1.根据指定规则根据runtime进行页面选择跳转

背景:要根据后台返回的数据 进行选择要跳转到哪一个ViewController

// 这个规则肯定事先跟服务端沟通好,跳转对应的界面需要对应的参数

NSDictionary *userInfo = @{

@"class": @"HSFeedsViewController",

@"property": @{//类中所需要的参数

@"ID": @"123",

@"type": @"12"

}

};

思路:使用runtime去解决这个问题的思路就是 通过运行时 根据对应的类名去创建类以及类的属性,这就需要和服务端去协商返回的数据形式 要类似:

实现:  这里使用了三个objc/runtime.h中函数分别是:

  1. - (void)push:(NSDictionary *)params
  2.  
  3. {
  4.  
  5. // 类名
  6.  
  7. NSString *class =[NSString stringWithFormat:@"%@", params[@"class"]];
  8.  
  9. const char *className = [class cStringUsingEncoding:NSASCIIStringEncoding];
  10.  
  11. // 从一个字串返回一个类
  12.  
  13. Class newClass = objc_getClass(className);
  14.  
  15. if (!newClass)
  16.  
  17. {
  18.  
  19. // 创建一个类
  20.  
  21. Class superClass = [NSObject class];
  22.  
  23. newClass = objc_allocateClassPair(superClass, className, );
  24.  
  25. // 注册你创建的这个类
  26.  
  27. objc_registerClassPair(newClass);
  28.  
  29. }
  30.  
  31. // 创建对象
  32.  
  33. id instance = [[newClass alloc] init];
  34.  
  35. NSDictionary *propertys = params[@"property"];
  36.  
  37. [propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  38.  
  39. // 检测这个对象是否存在该属性
  40.  
  41. if ([self checkIsExistPropertyWithInstance:instance verifyPropertyName:key]) {
  42.  
  43. // 利用kvc赋值
  44.  
  45. [instance setValue:obj forKey:key];
  46.  
  47. }
  48.  
  49. }]
  50.  
  51. // 获取导航控制器
  52.  
  53. UITabBarController *tabVC = (UITabBarController *)self.window.rootViewController;
  54.  
  55. UINavigationController *pushClassStance = (UINavigationController *)tabVC.viewControllers[tabVC.selectedIndex];
  56.  
  57. // 跳转到对应的控制器
  58.  
  59. [pushClassStance pushViewController:instance animated:YES];
  60.  
  61. }

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

  1. /**
  2.  
  3. * 检测对象是否存在该属性
  4.  
  5. */
  6.  
  7. - (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName
  8.  
  9. {
  10.  
  11. unsigned int outCount, i;
  12.  
  13. // 获取对象里的属性列表
  14.  
  15. objc_property_t * properties = class_copyPropertyList([instance
  16.  
  17. class], &outCount);
  18.  
  19. for (i = ; i < outCount; i++) {
  20.  
  21. objc_property_t property =properties[i];
  22.  
  23. // 属性名转成字符串
  24.  
  25. NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
  26.  
  27. // 判断该属性是否存在
  28.  
  29. if ([propertyName isEqualToString:verifyPropertyName]) {
  30.  
  31. free(properties);
  32.  
  33. return YES;
  34.  
  35. }
  36.  
  37. }
  38.  
  39. free(properties);
  40.  
  41. return NO;
  42.  
  43. }

objc_property_t  class_copyPropertyList(Class class,unsigned int *outCount)    返回值为一个数组 数组中为对应的类的属性列表 以此来对比类中是否含有当前属性,从而通过KVC为类的属性赋值.

2.修改系统类的方法实现

背景:如果需求中要统计每个viewController 展示给用户的次数,我们想到的就是在ViewController中添加对应的统计的代码,但是会很麻烦,此时可以创建一个UI ViewController的分类更改底层中viewWillAppear的实现 这就用到runtime中method Swizzling (方法混合)

实现:通过methodSwizzling 修改了UIViewController的@selector(viewWillAppear:)对应的函数指针,使他的实现指向了自定的方法

  1. #import "UIViewController+Tracking.h"
  2.  
  3. #import <objc/runtime.h>
  4.  
  5. @implementation UIViewController (Tracking)
  6.  
  7. + (void)load
  8.  
  9. {
  10.  
  11. static dispatch_once_t onceToken;
  12.  
  13. dispatch_once(&onceToken, ^{
  14.  
  15. Class class = [self class];
  16.  
  17. SEL originalSelector = @selector(viewWillAppear:);
  18.  
  19. SEL swizzlingSelector = @selector(swizzling__viewWillAppear:);
  20.  
  21. Method originMethod = class_getInstanceMethod(class, originalSelector);
  22.  
  23. Method swizzlingMethod = class_getInstanceMethod(class, swizzlingSelector);
  24.  
  25. //将 swizzlingMethod 中的实现过程添加到 originalSelector 这个方法中
  26.  
  27. BOOL didAddMethod = class_addMethod(class,originalSelector, method_getImplementation(swizzlingMethod), method_getTypeEncoding(swizzlingMethod));
  28.  
  29. if (didAddMethod) {
  30.  
  31. //用 originMethod中的实现 替换 swizzlingSelector这个方法中的实现 这样原始的和自定义的方法都执行的时同一个实现过程
  32.  
  33. class_replaceMethod(class, swizzlingSelector, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
  34.  
  35. }else{//可能出现添加失败的情况(比如 被添加的方法中已经存在了对应方法的实现 就会返回NO)
  36.  
  37. //将 originMethod 和 swizzlingMethod中的实现过程进行交换
  38.  
  39. method_exchangeImplementations(originMethod, swizzlingMethod);
  40.  
  41. }
  42.  
  43. });
  44.  
  45. }
  46.  
  47. /*
  48.  
  49. 经过上面的 class_method 和 class_replaceMethod 或 method_exchangeImplementations 就实现了
  50.  
  51. //http://blog.jobbole.com/79580/
  52.  
  53. */
  54.  
  55. - (void)swizzling__viewWillAppear:(BOOL)animation
  56.  
  57. {
  58.  
  59. [self swizzling__viewWillAppear:animation];
  60.  
  61. NSLog(@"swizzling_viewWillAppear");
  62.  
  63. }

(1)通过两个方法  class_addMethod class_replaceMethod这个方法实现方法Method这个结构体中 IMP对应的函数指针对应的函数实现进行添加 或者 替换SEL 代表了Method的名称name,IMP代表函数指针 即为函数在内存中的开始位置

另外还有一些注意事项 为什么一定要写在load中 还要写在dispatch_once中,因为swilzzing method会影响代码的整体状态 甚至有可能改变程序的运行流程,要保证避免并发的竞争,而+load方法是在类初始化就进行了加载(这里不太明白具体原理)详细参看下面链接

http://nshipster.com/method-swizzling/

iOS RunTime的简单使用的更多相关文章

  1. iOS Runtime的消息转发机制

    前面我们已经讲解Runtime的基本概念和基本使用,如果大家对Runtime机制不是很了解,可以先看一下以前的博客,会对理解这篇博客有所帮助!!! Runtime基本概念:https://www.cn ...

  2. iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制

    你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...

  3. ios runtime swizzle

    ios runtime swizzle @implementation NSObject(Extension) + (void)swizzleClassMethod:(Class)class orig ...

  4. ios runtime的相关知识

    一.iOS runtime原理 对于runtime机制,在网上找到的资料大概就是怎么去用这些东西,以及查看runtime.h头文件中的实现,当然这确实是一种很好的学习方法,但是,其实我们还是不会知道r ...

  5. ios下最简单的正则,RegexKitLite

    ios下最简单的正则,RegexKitLite 1.去RegexKitLite下载类库,解压出来会有一个例子包及2个文件,其实用到的就这2个文件,添加到工程中.备用地址:http://www.coco ...

  6. iOS Runtime 实践(1)

    很多时候我们都在看iOS开发中的黑魔法——Runtime.懂很多,但如何实践却少有人提及.本文便是iOS Runtime的实践第一篇. WebView 我们这次的实践主题,是使用针对接口编程的方式,借 ...

  7. iOS中XMPP简单聊天实现 好友和聊天

    版权声明本文由陈怀哲首发自简书:http://www.jianshu.com/users/9f2e536b78fd/latest_articles;微信公众号:陈怀哲(chenhuaizhe2016) ...

  8. 包建强的培训课程(11):iOS Runtime实战

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

  9. iOS Runtime 实操练习

    iOS  Runtime 知识详解: http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/ 一般可以运行Runtime进行以下操作 ...

随机推荐

  1. 安卓Android控件ListView获取item中EditText值

    可以明确,现在没有直接方法可以获得ListView中每一行EditText的值. 解决方案:重写BaseAdapter,然后自行获取ListView中每行输入的EditText值. 大概算法:重写Ba ...

  2. Rational Rose--简介

    Rational Rose Rational Rose是Rational公司出品的一种面向对象的统一建模语言的可视化建模工具.用于可视化建模和公司级水平软件应用的组件构造. 目前版本的Rational ...

  3. android图片处理方法(不断收集中)

    //压缩图片大小 public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArr ...

  4. 使用Unison同步服务器目录

    一.Unison简介Unison是Windows.Linux以及其他Unix平台下都可以使用的文件同步工具,它能使两个文件夹(本地或网络上的)保持内容的一致.Unison拥有与其它一些同步工具或文件系 ...

  5. [RxJS] Subject basic

    A Subject is a type that implements both Observer and Observable types. As an Observer, it can subsc ...

  6. [React] Set up React apps with zero configuration

    The React team has an official Command Line Interface (CLI) for building React projects called " ...

  7. 今天升级了ADT到ADT 22.6.1,打包混淆的时候就出现了问题

    Proguard returned with error code 1. See console Error: Unable to access jarfile ..\lib\proguard.jar ...

  8. 《RESTful Web Services》第一章 使用统一接口

    序言 HTTP是一种应用层协议.SOAP和一些Ajax Web框架都将HTTP作为一种传输信息的协议,难以充分利用HTTP层的基础设施. 1.2 如何保持交互的可见性     可见性是HTTP的一个核 ...

  9. Lipo Error!! can't open input file

    参考文章:http://stackoverflow.com/questions/17348912/lipo-error-cant-open-input-file I got it to Work, i ...

  10. Apache rewrite 详解

    用rewrite可实现的部分:URL根目录搬迁,多目录查找资源,阻止盗连你的图片,拒绝某些主机访问,基于时间重写,据浏览器类型重写,动态镜像远程资源,外部重写程序模板,等等 详见下表: 目标 重写设置 ...