updating UI from a C function in a thread

2019-05-26 17:01发布

问题:

I am using a library called libmosquitto in an iPhone app.

The library is written in C. It receives push notifications and therefor runs in a thread.

I want to take the data it receives, and display it in a UITableView, however ( I think) I have to write the callbacks which libmosquitto uses as C functions rather than Objective C methods, so I cannot access 'self' in order to do: [self performSelectorOnMainThread:@selector(hideActivityViewer) withObject:nil waitUntilDone:NO];

Anyone have problems like this, is there another way I could update the UI?

From inside one of my Objective C methods I call this:

mosquitto_message_callback_set(mosq, my_message_callback); 

And my_message_callback is defined as:

void my_message_callback(void *obj, struct mosquitto_message *message)
{
NSLog(@"Do this thing:");
if(message->payloadlen){
    const char *payload = (const char *)message->payload;
    [array addObject:[NSString stringWithUTF8String: payload]];
    //[self performSelectorOnMainThread:@selector(updateTable) withObject:nil waitUntilDone:NO];        

    //printf("%s %s\n", message->topic, message->payload);
}else{
    //printf("%s (null)\n", message->topic);
}
//fflush(stdout);

}

Thanks

回答1:

The function mosquitto_new takes a void * pointer as the second argument, which it will then pass to any callbacks that you have. You can use that to pass self as the thing that should arrive at your callback as void *obj. It's then explicitly safe to cast that to the correct [pointer to] class type since C allows any pointer type to be converted to void * (and back) without any side effects.

So then you'd do something like:

void my_message_callback(void *obj, struct mosquitto_message *message)
{
    [(ClassType *)obj
        performSelectorOnMainThread:@selector(updateTable)
        withObject:nil
        waitUntilDone:NO];
}


回答2:

Look into Grand Central Dispatch (GCD, aka libdispatch). It's a C library so ought to be able to be called from your C code without issue. You'd want to do something like:

dispatch_async(dispatch_get_main_queue(), ^{
    //code you want on the main thread.
});


回答3:

You can get access to NSApp from everywhere, and I believe that any message not understood by NSApplication will be send to its delagate which is your instance of NSApplicationDelegate. If this does not do it, you could add a class application that returns the object that can run your method if this object is unique.

You can also use Use grand central dispatch and the function

dispatch_async(dispatch_get_main_queue(), ^{
    //some code
})