2

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

Michael
  • 328
  • 2
  • 11
  • You might be able to pass a reference to your objective C object when you set up the C callback. For example the `void *obj` argument in the callback above might be the pointer you can use to get back to `self` – Stephen O'Connor Nov 04 '11 at 14:10
  • Thanks Steve, I have discovered how to pass in self to the callback. You were right. – Michael Nov 04 '11 at 19:50

3 Answers3

3

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.
});
jemmons
  • 18,605
  • 8
  • 55
  • 84
  • No, you don't want to set the callback on the main thread, you want to invoke it on the main thread or get it to invoke another function on the main thread. – JeremyP Nov 04 '11 at 14:21
  • My bad. I didn't look closely enough at what he was trying to accomplish on main. Edited. – jemmons Nov 04 '11 at 15:00
  • +1 now. This is a nice elegant solution, much better than the one I was going to write. – JeremyP Nov 04 '11 at 15:07
  • Thanks, I managed to do what I needed in the end using the thread. – Michael Nov 04 '11 at 19:49
1

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
})
simonpie
  • 354
  • 1
  • 5
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];
}
Tommy
  • 99,986
  • 12
  • 185
  • 204
  • Hi, That sounds like what I need, but when I try it, my my_message_callback no longer fires: mosq = mosquitto_new(id, self); – Michael Nov 04 '11 at 14:56
  • The other two callbacks are still working. From looking at the code, I thought it was the struct mosq that was being passed back in as obj. – Michael Nov 04 '11 at 15:00
  • I took my answer from the documentation at http://mosquitto.org/api/files/mosquitto-h.html — it specifies that the second thing passed to `mosquitto_new` is named `void *obj` and is "A user pointer that will be passed as an argument to any callbacks that are specified." – Tommy Nov 04 '11 at 15:04
  • Yes, you are right. Does not seem to work in practice though. That particular callback no longer gets fired when I pass in self. I take it out and it works fine again. – Michael Nov 04 '11 at 15:11
  • My reading is that you should be passing `self` just to `mosquitto_new`, then pass the mosquitto instance to `mosquitto_message_callback_set` — the pointer to self is stored in some way inside the mosquitto instance. Are we on a wavelength? – Tommy Nov 04 '11 at 15:14
  • Yes, I think so: mosq = mosquitto_new(id, self); mosquitto_message_callback_set(mosq, my_message_callback); However, it just stops working when I do this. No errors, or warnings. Just no callback. – Michael Nov 04 '11 at 15:19
  • As far as I can see from the code, it passes mosq to the callbacks if you pass in NULL to mosquitto_new, and otherwise it passes in what you passed. That is a little bit odd. – Michael Nov 04 '11 at 15:26
  • My connected callback needed mosq, but it was now getting self passed in instead, so I got around that one so I am back on track. Now I am trying to execute your suggestion above, but it is telling me that updateTable is undefined. Running out on time though, so I think that will be a job for tomorrow. – Michael Nov 04 '11 at 15:47
  • Sorry, it say -[UITableView updateTable]: unrecognized selector sent to instance 0x5035e00 Nothing about not found in there. – Michael Nov 04 '11 at 15:52
  • Sorry, I was passing in something else instead of self as an experiment and forgot to change it back. Success. Thanks so much for your help. – Michael Nov 04 '11 at 15:55