NSOiOOC对象模型及运行时(3/3)-应用 2014-01-13
在part2中,我们知道由三种途径可以和运行时打交道,使用最灵活的要数最后一种了,通过#import<objc/runtime.h>
,我们就可以使用强大的运行时提供的全部功能了。不过,运行时是一把双刃剑,它能影响到你的所有代码的运行,所以除非很必要,一般最好还是尽少使用吧。
method swizzling
这次主要说一下method swizzling
的用法,它通过添加/修改/删除SEL -> IMP
的映射关系,来让运行时去执行指定的方法;这种方法在某些场景下非常有效,当我们有需要在类目中重载一个类的方法的需求时就可以使用method swizzling
,因为在类目中重载方法会导致原有的方法永远没有机会去执行了,而且原有的方法的具体实现我们是无法知道的,这就可能会导致不可预测的危险,所以最好的是使用methor swizzling
下面通过一个我在实际中用到的一个例子还说明一下具体的使用方法。
在iOS7中,UINavigationController
新增加了一个支持手势返回的API:
1 | @property(nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer NS_AVAILABLE_IOS(7_0); |
实际上它是UIScreenEdgePanGestureRecognizer
类型的,但只支持从左边侧开始的手势,如果我们想要实现从任意位置开始的返回,最简单的方法就是使用 method Swizzling
来实现,这个灵感来自于这里和这里.
- 首先先实现一个用于
method swizzling
的C函数:
1 | void MethodSwizzle(Class c, SEL origSEL, SEL overrideSEL){ |
- 然后实现一个
UIScreenEdgePanGestureRecognizer
的类目,我们只需要将UIScreenEdgePanGestureRecognizer
替换成UIPanGestureRecognizer
即可。
1 | + (void)load{ |
需要注意的是我们在程序中似乎是使用了递归调用,其实不然,因为我们之前在+load()
中已经交换了这两个方法的SEL -> IMP
映射。
我们可以通过enableGesturePop
来决定是使用自定义的返回功能还是使用系统提供的返回功能。
最后的效果如下图所示:
关于运行时的其他用法,比如通过category
给类添加属性和变量。因为类的结构体确定好之后,大小就不能改变了,这种方法其实是通过Associated Objects
来进行添加的;其他的应有还有IMP缓存、Dynamic NSCoding,想深入学习的话可以参考一下参考资料中的内容。
参考资料
Updata
Github上发现了一个从任意位置滑动手势返回的完整实现:SloppySwipe