处理回调

时间:2008-11-25 10:03:59

标签: objective-c cocoa

我在Objective-C类中有一个方法。它有2个用C编写的回调函数。类指针即self作为void *传递给这些函数。在C函数中,我创建了一个类型为class的指针,并分配void *参数。 第一个回调函数成功执行。但是void *指针在第二个回调函数中变为nil。请注意,我没有在第一次回调中调整指针,但仍然在第二次回调中得到nil

任何想法可能出错?

例如:

kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification,
                                      matchingDict, RawDeviceAdded, NULL,
                                      &gRawAddedIter);

RawDeviceAdded(NULL, gRawAddedIter, self);

这很好用。但是,以下功能会将self收到nil

kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification,
                                      matchingDict, BulkTestDeviceAdded, NULL,
                                      &gBulkTestAddedIter);

BulkTestDeviceAdded(NULL, gBulkTestAddedIter, self);

3 个答案:

答案 0 :(得分:11)

您的问题是否特别针对IOKit回调例程?你给出的具体例子的问题是IOServiceMatchingCallback只需要2个参数,而不是3.你需要你的RawDeviceAdded()和BulkTestDeviceAdded()回调函数来匹配IOServiceMatchingCallback原型并接受self作为第一个参数(refCon),而不是第三个。此外,您需要传入self作为IOServiceAddMatchingNotification()的倒数第二个参数,以便通过回调将其传递给您。

在Objective-C代码中处理C回调的常用方法就是使用一个静态函数将回调转发给您的实例。因此,您的示例回调代码如下所示:

static RawDeviceAdded(void* refcon, io_iterator_t iterator)
{
    [(MyClass*)refcon rawDeviceAdded:iterator];
}

@implementation MyClass
- (void)setupCallbacks
{
    // ... all preceding setup snipped
    kr = IOServiceAddMatchingNotification(gNotifyPort,kIOFirstMatchNotification, matchingDict,RawDeviceAdded,(void*)self,&gRawAddedIter );
    // call the callback method once to 'arm' the iterator
    [self rawDeviceAdded:gRawAddedIterator];
}
- (void)rawDeviceAdded:(io_iterator_t)iterator
{
    // take care of the iterator here, making sure to complete iteration to re-arm it
}
@end

答案 1 :(得分:1)

通常,Objective-C中的回调是通过传递委托对象和选择器来对该委托执行来处理的。例如,此方法将在记录消息后调用其委托上的方法,并传递自身和记录的消息。

- (void)logMessage:(NSString *)message
          delegate:(id)delegate
    didLogSelector:(SEL)didLogSelector
{
    NSLog(@"%@", message);

    if (delegate && didLogSelector && [delegate respondsToSelector:didLogSelector]) {
        (void) [delegate performSelector:didLogSelector
                              withObject:self
                              withObject:message];
    }
}

你可以用这样的代码来调用它:

- (void)sayHello
{
    [logger logMessage:@"Hello, world"
              delegate:self
        didLogSelector:@selector(messageLogger:didLogMessage:)];
}

- (void)messageLogger:(id)logger
        didLogMessage:(NSString *)message
{
    NSLog(@"Message logger %@ logged message '%@'", logger, message);
}

您也可以直接使用objc_msgSend(),但您需要了解Objective-C运行时,以便选择要使用的变体以及如何构造原型和函数指针来调用它。 (这是消息发送实际在Objective-C中实现的机制 - 编译器通常生成调用以表示[]表达式。)

答案 2 :(得分:0)

这就是Objective-C的选择器: http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/NSInvocationOperation_Class

API不是很直观,但一旦你理解它就很好

你可能也需要做一些重构,现在可能有更好的方法,但是当我遇到这个问题时,我的解决方案就是重构并使用InvoationOperation。