http://www.csdn.net/article/2015-07-06/2825133-objective-c-runtime/6
深入理解Objective-C的Runtime机制
发表于2015-07-06 11:53| 46846次阅读| 来源CSDN| 19 条评论| 作者刘耀柱
摘要:Objective-C是基于C加入了面向对象特性和消息转发机制的动态语言,除编译器之外,还需用Runtime系统来动态创建类和对象,进行消息发送和转发。本文作者通过分析Apple开源的Runtime代码来深入理解OC的Runtime机制。
三种方法的选择
Runtime提供三种方式来将原来的方法实现代替掉,那该怎样选择它们呢?
- Method Resolution:由于Method Resolution不能像消息转发那样可以交给其他对象来处理,所以只适用于在原来的类中代替掉。
- Fast Forwarding:它可以将消息处理转发给其他对象,使用范围更广,不只是限于原来的对象。
- Normal Forwarding:它跟Fast Forwarding一样可以消息转发,但它能通过NSInvocation对象获取更多消息发送的信息,例如:target、selector、arguments和返回值等信息。
Associated Objects
当使用Category对某个类进行扩展时,有时需要存储属性,Category是不支持的,这时需要使用Associated Objects来给已存在的类Category添加自定义的属性。Associated Objects提供三个API来向对象添加、获取和删除关联值:
- void objc_setAssociatedObject (id object, const void *key, id value, objc_AssociationPolicy policy )
- id objc_getAssociatedObject (id object, const void *key )
- void objc_removeAssociatedObjects (id object )
其中objc_AssociationPolicy是个枚举类型,它可以指定Objc内存管理的引用计数机制。
[cpp] view plaincopy
- typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
- OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
- OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.
- * The association is not made atomically. */
- OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
- * The association is not made atomically. */
- OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.
- * The association is made atomically. */
- OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.
- * The association is made atomically. */
- };
下面有个关于NSObject+AssociatedObject Category添加属性associatedObject的示例代码:
NSObject+AssociatedObject.h
[cpp] view plaincopy
- @interface NSObject (AssociatedObject)
- @property (strong, nonatomic) id associatedObject;
- @end
NSObject+AssociatedObject.m
[cpp] view plaincopy
- @implementation NSObject (AssociatedObject)
- - (void)setAssociatedObject:(id)associatedObject
- {
- objc_setAssociatedObject(self, @selector(associatedObject), associatedObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- }
- - (id)associatedObject
- {
- return objc_getAssociatedObject(self, _cmd);
- }
- @end
Associated Objects的key要求是唯一并且是常量,而SEL是满足这个要求的,所以上面的采用隐藏参数_cmd作为key。
Method Swizzling
Method Swizzling就是在运行时将一个方法的实现代替为另一个方法的实现。如果能够利用好这个技巧,可以写出简洁、有效且维护性更好的代码。可以参考两篇关于Method Swizzling技巧的文章:
Aspect-Oriented Programming(AOP)
类似记录日志、身份验证、缓存等事务非常琐碎,与业务逻辑无关,很多地方都有,又很难抽象出一个模块,这种程序设计问题,业界给它们起了一个名字叫横向关注点(Cross-cutting concern),AOP作用就是分离横向关注点(Cross-cutting concern)来提高模块复用性,它可以在既有的代码添加一些额外的行为(记录日志、身份验证、缓存)而无需修改代码。
危险性
Method Swizzling就像一把瑞士小刀,如果使用得当,它会有效地解决问题。但使用不当,将带来很多麻烦。在stackoverflow上有人已经提出这样一个问题:What are the Dangers of Method Swizzling in Objective C?,它的危险性主要体现以下几个方面:
- Method swizzling is not atomic
- Changes behavior of un-owned code
- Possible naming conflicts
- Swizzling changes the method's arguments
- The order of swizzles matters
- Difficult to understand (looks recursive)
- Difficult to debug
总结
虽然在平时项目不是经常用到Objective-C的Runtime特性,但当你阅读一些iOS开源项目时,你就会发现很多时候都会用到。所以深入理解Objective-C的Runtime数据结构、消息转发机制有助于你更容易地阅读和学习开源项目。
扩展阅读
- 玉令天下博客的Objective-C Runtime
- 顾鹏博客的Objective-C Runtime
- Associated Objects
- Method Swizzling
- Method Swizzling和AOP实践
- Objective-C Runtime Reference
- What are the Dangers of Method Swizzling in Objective C?
- iOS程序员6级考试(答案和解释)
作者简介:刘耀柱(@Sam_Lau_Dev),iOS Developer兼业余Designer,参与开发技术前线iOS项目翻译,个人博客:http://www.jianshu.com/users/256fb15baf75/latest_articles,GitHub:https://github.com/samlaudev。