当前位置: 首页 > 编程笔记 >

使用objc runtime实现iOS闭环的懒加载功能

东门焕
2023-03-14
本文向大家介绍使用objc runtime实现iOS闭环的懒加载功能,包括了使用objc runtime实现iOS闭环的懒加载功能的使用技巧和注意事项,需要的朋友参考一下

使用objc runtime实现懒加载

地址:AutoPropertyCocoa

懒加载形式如下

- (id)lazyloadProperty{

  if(_lazyloadProperty == nil){
  
    _lazyloadProperty = [XClass ...];
  }
  return _lazyloadProperty;
}

一般使用宏定义可以轻松完成。但是没有一致性,移植差。

利用objc runtime的动态性实现懒加载可以实现即可增加又可删除功能,也可以避免污染类型。该三方弥补了目前没有闭环实现懒加载三方的空缺。

主要流程:

  1. 实例或者类的懒加载
  2. 如果是实例对象则钩住并修改类型将其子类化
  3. 对该类型进行method swizzling
  4. 如果现在进行解绑,则判断是否是自己实现的方法.如果是自己实现的方法->5,否则->6
  5. 调用method swizzling还原
  6. 删除这个类型的这个方法

难点:

自己实现method swizzling

  1.  重新实现objc1时代的方法class_removeMethods
  2.  钩住运行时中的runtimelock,实现修改类型数据时的安全性

我们再实现method swizzling时的两个API

OBJC_EXPORT IMP _Nullable
class_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, 
          const char * _Nullable types) 
  OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

OBJC_EXPORT void
method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2) 
  OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

不管使用哪种,如果这个类型没有实现该方法而是父类实现的话,就需要动态增加一个方法。动态增加的方法在Objc1时代,是可以通过下列方法删除的:

OBJC_EXPORT void
class_removeMethods(Class _Nullable, struct objc_method_list * _Nonnull)
  OBJC2_UNAVAILABLE;

Objc2时代之后runtime被重写后没有该方法了,并且新的runtime的类结构看起来就没打算让开发者删除方法,所以这里将过程记下。

首先看类读写器的结构class_rw_t

struct class_rw_t {
  // Be warned that Symbolication knows the layout of this structure.
  uint32_t flags;
  uint32_t version;

  const class_ro_t *ro;

  method_array_t methods;//删除这里的一个方法
  property_array_t properties;
  protocol_array_t protocols;

  Class firstSubclass;
  Class nextSiblingClass;

  char *demangledName;

#if SUPPORT_INDEXED_ISA
  uint32_t index;
#endif
};

method_array_t继承于list_array_tt<method_t, method_list_t>,它是数组结构。存储的内容是method_list_t.

method_list_t又继承于entsize_list_tt<method_t, method_list_t, 0x3>,他也是数组结构。

整个method_array_t结构是二维数组。每次删掉一个method_t需要用新method_list_t替换原对象。

 

然后是线程安全的问题,需要获取到苹果在操作类型的时候使用的读写锁(pthread_rw_lock_t runtimelock)。没有这把锁任何对runtime的修改都是不可靠的。

最终采取的方式是:劫持暴露了符号的系统函数然后阻塞线程

 

劫持系统C函数使用的是脸书的鱼钩,这个钩子在macOS其实也是可以正常工作的。

剩下的就是寻找合适的函数了,这函数要满足两个条件:

  1. 该函数在符号表中存在
  2. 函数内部在lock runtimelock之后存在满足条件1的第二个函数

找了半天发现最合适的只有objc_allocateProtocol()了,objc_allocateProtocol内部会调用calloc(),所以第二个被劫持函数就是calloc。为了减小calloc的开销,需要稍微做一些工作。

  1. 对每次调用进行比较线程ID的操作显然比暴力阻塞线程好。
  2. 减小劫持后的calloc的调用栈。

总结

以上所述是小编给大家介绍的使用objc runtime实现iOS闭环的懒加载功能,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

 类似资料:
  • 本文向大家介绍PHP实现懒加载的方法,包括了PHP实现懒加载的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP实现懒加载的方法。分享给大家供大家参考。具体分析如下: 寻常php的加载是通过include(),require()等方法来加载外部文件,之后再通过实例调用方法或直接调用静态方法,而这样子写引入语句实在很麻烦,有的框架会将特定路径的文件全部引入,直接实例化就能使用,但这样

  • 本文向大家介绍vue实现路由懒加载及组件懒加载的方式,包括了vue实现路由懒加载及组件懒加载的方式的使用技巧和注意事项,需要的朋友参考一下 一、为什么要使用路由懒加载   为给客户更好的客户体验,首屏组件加载速度更快一些,解决白屏问题。 二、定义   懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载。 三、使用   常用的懒加载方式有两种:即使用vue异步组件 和 ES中的imp

  • 本文向大家介绍怎么实现路由懒加载呢?相关面试题,主要包含被问及怎么实现路由懒加载呢?时的应答技巧和注意事项,需要的朋友参考一下 1.vue的异步组件:resolve=>require(['需要异步加载的组件'],resolve) 2.es6的import方法:()=>import(需要异步加载的组件) 3.webpack的 require.ensure: r => require.ensure([

  • 本文向大家介绍基于javascript实现图片懒加载,包括了基于javascript实现图片懒加载的使用技巧和注意事项,需要的朋友参考一下 一、定义   图片延迟加载也称为懒加载,延迟加载图片或符合某些条件时才加载某些图片,通常用于图片比较多的网页。可以减少请求数或者延迟请求数,优化性能。  二、呈现形式 【1】延时加载,使用setTimeout或setInterval进行加载延迟,如果用户在加载

  • 本文向大家介绍js实现图片懒加载效果,包括了js实现图片懒加载效果的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了js图片懒加载的具体代码,供大家参考,具体内容如下 图片懒加载,思路:当鼠标滑动到对应图片的高度时,进行图片的加载; 当有类似于瀑布流的布局时常用的加载模式 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 本文向大家介绍android实现ViewPager懒加载的三种方法,包括了android实现ViewPager懒加载的三种方法的使用技巧和注意事项,需要的朋友参考一下 在项目中ViewPager和Fragment接口框架已经是处处可见,但是在使用中,我们肯定不希望用户在当前页面时就在前后页面的数据,加入数据量很大,而用户又不愿意左右滑动浏览,那么这时候ViewPager中本来充满善意的预加载就有点