浅析为何能通过FDStackView在iOS9以下使用UIStackView

前几天看到sunnyxx团队的新作FDStackView。大家都知道在iOS9苹果提供了一个新的玩具UIStackView,然而在iOS9以前是没有办法使用的。可通过FDStackView你却可以在iOS9以前的系统上使用UIStackView,更重要的是我们不需要去做任何额外的工作,FDStackView会自动为我们处理好一切。

今天分析了一下是如何实现这个神奇的功能的,在FDStackView.m中嵌入了一段内联汇编:

__asm(
  ".section        __DATA,__objc_classrefs,regular,no_dead_strip\n"
#if TARGET_RT_64_BIT
  ".align          3\n"
  "L_OBJC_CLASS_UIStackView:\n"
  ".quad           _OBJC_CLASS_$_UIStackView\n"
#else
  ".align          2\n"
  "_OBJC_CLASS_UIStackView:\n"
  ".long           _OBJC_CLASS_$_UIStackView\n"
#endif
  ".weak_reference _OBJC_CLASS_$_UIStackView\n"
  );

这段代码的主要作用是在DATA这个segment中暴露了L_OBJC_CLASS_UIStackView这个符号,它指向了符号OBJC_CLASS$_UIStackView(编译器硬编码确定)。

然后在类被成功加载之后会调用FDStackViewPatchEntry,这里面首先判断如果是iOS9的话那就啥也不需要做了。

这里面比较关键的代码在这里:

#if TARGET_CPU_ARM
        __asm("movw %0, :lower16:(_OBJC_CLASS_UIStackView-(LPC0+4))\n"
              "movt %0, :upper16:(_OBJC_CLASS_UIStackView-(LPC0+4))\n"
              "LPC0: add %0, pc" : "=r"(stackViewClassLocation));
#elif TARGET_CPU_ARM64
        __asm("adrp %0, L_OBJC_CLASS_UIStackView@PAGE\n"
              "add  %0, %0, L_OBJC_CLASS_UIStackView@PAGEOFF" : "=r"(stackViewClassLocation));
#elif TARGET_CPU_X86_64
        __asm("leaq L_OBJC_CLASS_UIStackView(%%rip), %0" : "=r"(stackViewClassLocation));
#elif TARGET_CPU_X86
        void *pc = NULL;
        __asm("calll L0\n"
              "L0: popl %0\n"
              "leal _OBJC_CLASS_UIStackView-L0(%0), %1" : "=r"(pc), "=r"(stackViewClassLocation));
#else
#error Unsupported CPU
#endif

这里判断了CPU的指令集,以ARM为例说明。
由于不能将一个32位的常量直接存入一个寄存器中,所以需要分别取它的高16位和低16位存入。
完了之后将pc和%0相加存入%0中,然后将输入保存到stackViewClassLocation。

接着通过runtime的objc_allocateClassPair创建了一个名为UIStackView的类,并在stackViewClassLocation指针所指向的空间中写入新创建的class,然后FDStackView就华丽变身为UIStackView了。

结尾:
由于我本人对汇编也不是很熟悉,只是简单的分析了一下,所以如果有不对的地方麻烦大家不吝赐教共同学习:)

BTW,这样的方式如果是为UIStackView写了category也没办法使用了,因为分类是写在原来的类上面的,暂时还不知道怎么解决。

参考链接:
http://www.ethernut.de/en/documents/arm-inline-asm.html
http://hailoong.sinaapp.com/?p=125



作者:一个大番茄
链接:https://www.jianshu.com/p/e4306e4838f3
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值