Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling Callbacks

I have a method in an objective-C class. It has 2 callback functions written in C. The class pointer i.e. self is passed to these functions as void *. In the C functions I create a pointer of type class and assign the void * parameter. The first callback function executes successfully. But the void * pointer becomes nil in the 2nd callback function. Note that I haven't tweaked pointer in the first callback but still I get nil in 2nd callback.

Any ideas what might be going wrong?

For example:

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

RawDeviceAdded(NULL, gRawAddedIter, self);

This works fine. But below function receives self as nil.

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

BulkTestDeviceAdded(NULL, gBulkTestAddedIter, self);
like image 483
shrads Avatar asked Nov 25 '08 10:11

shrads


People also ask

How do you handle errors in callback?

If an error-handling callback function has been specified in the application and if the value of the error parameter is NULL, the error parameter is passed to the specified callback function, and the operation that encountered the error condition returns a value of DW_DLV_ERROR.

How do you explain callbacks?

In computer programming, a callback is a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time. The invocation may be immediate as in a synchronous callback or it might happen at later time, as in an asynchronous callback.

What is the purpose of callbacks?

A callback's primary purpose is to execute code in response to an event. These events might be user-initiated, such as mouse clicks or typing. With a callback, you may instruct your application to "execute this code every time the user clicks a key on the keyboard." button.


2 Answers

Are your problems specifically with the IOKit callback routines? The problem with the specific example you gave is that the IOServiceMatchingCallback takes only 2 parameters, not 3. You need your RawDeviceAdded() and BulkTestDeviceAdded() callback functions to match the IOServiceMatchingCallback prototype and to accept self as the first parameter (refCon), not the 3rd. Also, you need to pass in self as the second-to-last parameter of IOServiceAddMatchingNotification() to get it passed back to you by the callback.

A common method for handling C callbacks in Objective-C code is just to have a static function that forwards the callback to your instance. So, your example callback code would look like this:

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
like image 140
Boaz Stuller Avatar answered Nov 15 '22 13:11

Boaz Stuller


Generally, callbacks in Objective-C are handled by passing a delegate object and a selector to perform on that delegate. For example, this method will call a method on its delegate after logging a message, passing both itself and the message that was logged.

- (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];
    }
}

You might call it in code like this:

- (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);
}

You can also use objc_msgSend() directly instead, though you need to understand the Objective-C runtime enough to choose which variant to use and how to construct the prototype and function pointer through which to call it. (It's the mechanism by which message sends are actually implemented in Objective-C — what the compiler normally generates calls to in order to represent [] expressions.)

like image 33
Chris Hanson Avatar answered Nov 15 '22 13:11

Chris Hanson