iOS开发之Runtime运行时机制

时间:2022-12-02 23:21:27

摘要: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内存管理的引用计数机制。

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

@interface NSObject (AssociatedObject) 
@property (strong, nonatomic) id associatedObject;
@end
NSObject+AssociatedObject.m

@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技巧的文章:

nshipster Method Swizzling
Method Swizzling和AOP实践

Aspect-Oriented Programming(AOP)
类似记录日志、身份验证、缓存等事务非常琐碎,与业务逻辑无关,很多地方都有,又很难抽象出一个模块,这种程序设计问题,业界给它们起了一个名字叫横向关注点(Cross-cutting concern),AOP作用就是分离横向关注点(Cross-cutting concern)来提高模块复用性,它可以在既有的代码添加一些额外的行为(记录日志、身份验证、缓存)而无需修改代码。

危险性
Method Swizzling就像一把瑞士小刀,如果使用得当,它会有效地解决问题。但使用不当,将带来很多麻烦。在*上有人已经提出这样一个问题: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 级考试(答案和解释)

Objective C类方法load和initialize的区别

作者:Sam_Lau
链接:http://www.jianshu.com/p/25a319aee33d
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。