使用Method作为上下文的KVO Dispatcher模式

时间:2010-12-30 22:56:35

标签: objective-c pointers selector key-value-observing

我一直在尝试使用看起来像very clever KVO pattern的东西来解析一个可以作为上下文传递的Method指针的选择器。

模式部分的最后一部分给了我一些麻烦:

- (void)observeValueForKeyPath:(NSString *)keyPath 
    ofObject:(id)object 
    change:(NSDictionary *)change 
    context:(void *)context
{
    Method m = (Method)context;
    (void(*)(id,SEL,id,id,id))(m->method_imp)(owner, m->method_name, keyPath, object, change);
}

特别是解除引用方法指针并且看似调用的部分。

(void(*)(id,SEL,id,id,id))(m->method_imp)(owner, m->method_name, keyPath, object, change);

我收到此编译错误error: dereferencing pointer to incomplete type

我是Objective-C和C的新手,有两个问题:

  1. 上面的语法叫什么?我想了解更多相关信息。
  2. 如何修复该线路?
  3. 虽然我不明白,但我觉得这句话可以分成两行或更多行,以便更具可读性。如果这是真的,我很想看看它的外观。

1 个答案:

答案 0 :(得分:2)

它可能与导入Objective-C运行时标头一样简单:

#import <objc/runtime.h>

然后编译器知道Method是什么,并且您将能够成功解除引用它。


(void(*)(id,SEL,id,id,id))(m->method_imp)

m->method_imp转换为指向(void)函数的指针,其参数类型为id,SEL,id,id,id。每个Objective-C方法实际上都是一个C函数,第一个参数是指向对象的指针(可以使用self访问),第二个参数是选择器(可以通过_cmd访问) )遵循正常方法的参数。

因此,编译器现在断言你有这个函数有几个参数,所以你可以使用普通的括号来调用这个函数。第一个参数表示对象,第二个参数表示选择器,然后是所有其他参数。

要了解有关它的更多信息,请搜索函数指针并了解Objective-C运行时的工作原理。


实质上,您也可以使用以下代码:

objc_msgSend(owner, m->method_name, keyPath, object, change);

但是,没有必要获得实例方法。现在,你唯一需要的方法就是你已经拥有的选择器。这意味着,您可以直接使用SEL作为上下文参数,然后使用代码:

objc_msgSend(owner, (SEL)context, keyPath, object, change);

关于IMP的内容,m->method_imp定义为:

<objc/objc.h>中,IMP的定义如下:

typedef id          (*IMP)(id, SEL, ...); 

有点奇怪的语法,因为它不清楚哪一个是类型,哪一个是定义。好吧,在这种情况下,只有IMP是定义,其余是id (*)(id, SEL, ...)类型。要了解更多相关信息,请查找一些函数指针文章。

因此,它是一个指向函数的指针,该函数返回一个对象(id)并接受多个参数:默认的Objective-C,可能还有一些(由...表示,这意味着可能是其他参数)