iOS RunTime 机制浅析(二)

继续上一篇未写完的内容。

上一篇写到runtime通过与Foundation Framework interact中的消息转发机制。

在第一点中我们提到我们代码中调用函数在runtime sys的执行过程,那么如果没有寻找到指定的函数呢?

这时候Runtime sys 会启用NSObject中的

 forwardInvocation:

函数,这个函数附带一个 NSInvocation 类型的参数。

想象一下,如果有一个 negotiate函数想通过某个obj来调用,如果在函数中没有真正实现,那么可以转发到其他对象去执行,比如:

- (id)negotiate
{
    if ( [someOtherObject respondsTo:@selector(negotiate)] )
        return [someOtherObject negotiate];
    return self;
}

但是如果想真正地让某个对象来执行此函数,那么只有通过继承实现过此函数的类了。

以上这些做法都有缺点,就是当要实现的函数多的时候,那么必然要实现多个函数体进行转发,或者继承多个类去执行,这一点在objc的单继承下是不可能的。而且当函数多起来,会有很多不确定因素,一旦其他类中修改了某个函数,那么当前类的依赖关系也就受到较大的影响甚至无法执行。

另一个解决办法就是通过以上提到过的

forwardInvocation:
来实现消息的转发。

我们已经知道在类中寻找不到某个函数时,runtime sys会执行上述函数,那么在类中我们可以覆盖此函数为:

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ([someOtherObject respondsToSelector:
            [anInvocation selector]])
        [anInvocation invokeWithTarget:someOtherObject];
    else
        [super forwardInvocation:anInvocation];
}

这样子如果最终执行了函数,那么返回值会返回到最初的sender。

forwordInvacation:函数可以作为一个消息转发中心,把消息打包转发到不同的对象上,或者转发到同个目标。

还可以通过重写它,那么函数调用找不到指定函数时就不会出错了。

既然forwordInvacation:函数有以上特性,那么我们可以用它来模仿多重继承,这样在实际应用时可以为对象减少某些责任。如官方文档中给出的例子,下图fig-2.1。

fig-2.1


结合runtime的消息机制我们也不难理解,在模范多重继承时是如何执行的。

不过消息转发和多重继承还是有一定区别的,多重继承是把消息分散到多个类去执行,而消息转发是把功能集中在一个类,通过转发进行。

另一方面的功能就是surrogate代理。当我们有一个类包含了很多数据,还有很多功能时,我们希望能给他减肥,这时可以利用消息转发的机制为它创建一个surrogate。当消息到来时,就会自动转发了,从而减轻了该类的责任。


固然消息转发有它的优势,但是系统对于继承和转发还是有较大的区别的,比如以下函数:

respondsToSelector:
isKindOfClass:
只能在基础时返回真,通过消息转发不能返回真。

当然解决的办法还是有的,就是覆盖原来的方法,比如:

- (BOOL)respondsToSelector:(SEL)aSelector
{
    if ( [super respondsToSelector:aSelector] )
        return YES;
    else {
        /* Here, test whether the aSelector message can     *
         * be forwarded to another object and whether that  *
         * object can respond to it. Return YES if it can.  */
    }
    return NO;
}
这样子就可以实现转发判断功能了。

需要注意的是,在消息转发是,不能重写被转发的方法,否则转发无法进行。

至此,runtime的第二点功能实现就讲到这里,更多不明白的请参照官方文档。


第三

第三点比较好理解,就是利用runtime提供的纯C语言函数来实现运行时的动态调用,这些函数存放在 /usr/include/objc目录中。

这一点之前有个type Encoding专题,就是在调用这些纯C函数时难免与objc存在类型上的不兼容,是如何解决的。

由于篇幅较为零散,大家有兴趣自行查看。

runtime提供的这些动态实时查询函数类似于一下这些:

objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)
const char *property_getName(objc_property_t property)
objc_property_t class_getProperty(Class cls, const char *name)
objc_property_t protocol_getProperty(Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty)
const char *property_getAttributes(objc_property_t property)


就是运行时去获取类的属性列表,属性名等等信息。

我们有必要知道这些属性在编译器中是如何表示的,如下图。

Code

Meaning

R

The property is read-only (readonly).

C

The property is a copy of the value last assigned (copy).

&

The property is a reference to the value last assigned (retain).

N

The property is non-atomic (nonatomic).

G<name>

The property defines a custom getter selector name. The name follows the G (for example, GcustomGetter,).

S<name>

The property defines a custom setter selector name. The name follows the S (for example, ScustomSetter:,).

D

The property is dynamic (@dynamic).

W

The property is a weak reference (__weak).

P

The property is eligible for garbage collection.

t<encoding>

Specifies the type using old-style encoding.

那么当我们通过以上函数去查询是,就会有一下的结果


Property declaration

Property description

@property char charDefault;

Tc,VcharDefault

@property double doubleDefault;

Td,VdoubleDefault

@property enum FooManChu enumDefault;

Ti,VenumDefault

@property float floatDefault;

Tf,VfloatDefault

@property int intDefault;

Ti,VintDefault

@property long longDefault;

Tl,VlongDefault

@property short shortDefault;

Ts,VshortDefault

@property signed signedDefault;

Ti,VsignedDefault

@property struct YorkshireTeaStruct structDefault;

T{YorkshireTeaStruct="pot"i"lady"c},VstructDefault

@property YorkshireTeaStructType typedefDefault;

T{YorkshireTeaStruct="pot"i"lady"c},VtypedefDefault

@property union MoneyUnion unionDefault;

T(MoneyUnion="alone"f"down"d),VunionDefault

@property unsigned unsignedDefault;

TI,VunsignedDefault

@property int (*functionPointerDefault)(char *);

T^?,VfunctionPointerDefault

@property id idDefault;

Note: the compiler warns: "no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed"

T@,VidDefault

@property int *intPointer;

T^i,VintPointer

@property void *voidPointerDefault;

T^v,VvoidPointerDefault

@property int intSynthEquals;

In the implementation block:

@synthesize intSynthEquals=_intSynthEquals;

Ti,V_intSynthEquals

@property(getter=intGetFoo, setter=intSetFoo:) int intSetterGetter;

Ti,GintGetFoo,SintSetFoo:,VintSetterGetter

@property(readonly) int intReadonly;

Ti,R,VintReadonly

@property(getter=isIntReadOnlyGetter, readonly) int intReadonlyGetter;

Ti,R,GisIntReadOnlyGetter

@property(readwrite) int intReadwrite;

Ti,VintReadwrite

@property(assign) int intAssign;

Ti,VintAssign

@property(retain) id idRetain;

T@,&,VidRetain

@property(copy) id idCopy;

T@,C,VidCopy

@property(nonatomic) int intNonatomic;

Ti,VintNonatomic

@property(nonatomic, readonly, copy) id idReadonlyCopyNonatomic;

T@,R,C,VidReadonlyCopyNonatomic

@property(nonatomic, readonly, retain) id idReadonlyRetainNonatomic;

T@,R,&,VidReadonlyRetainNonatomic

以上表格由苹果官方文档提供。

由于函数较多,就不一一介绍,有兴趣查看官方文档https://developer.apple.com/library/ios/documentation/Cocoa/Reference/ObjCRuntimeRef/

runtime的第三方面就大概是这样,更多的是工具函数的意思。


通过三方面的介绍,对于runtime也有较大方面的理解了。

总而言之,runtime是objc特有的一种动态机制,其只要体现在三个方面,代码中的函数调用消息机制,基于Foundation Framework的函数调用及转发等机制,还有runtime提供的纯C方法库实时机制。runtime也需要编译器中的runtime system来支持。理解runtime可以让我们更灵活的编写代码,当然也要注意有关的注意事项。


以上包括第一篇均为本人参考官方文档所理解的内容,有错误的地方还望大家多多指教,谢谢!


官方介绍文档

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/ObjCRuntimeRef/
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008048-CH1-SW1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值