Best way to performselectoronmainthread in objective c?
Asked Answered
C

4

7

I'm writing a client-server app to iPhone. And I have a question about threading. When I access my online database from the device, I need to do this on a separate thread to not freeze the UI/main thread. But when responding to the data I've fetched from the database I call this method on the main thread: performSelectorOnMainThread. The thing is that this only lets me send one argument/object to the method (WithObject), sometimes I have more arguments I want to pass. and another thing about it is that I HAVE TO pass this one object. I can't pass nil, if I do the app crashes.

This is my code today.. and I'm worried that I'm using the methods and threading the wrong way.

- (IBAction)testServerAction:(id)sender {

    [self.imageView setHidden:YES];
    [self.activityView setHidden:NO];
    [self.activityView startAnimating];
    dispatch_queue_t testServer = dispatch_queue_create("Test-Server-Thread", NULL);
    dispatch_async(testServer, ^{

        if ([self.arrayWithServerConnections count] > 0)
        {
            NSString *messageToShow;
            if ([self testServerMethod])
            {
                messageToShow = @"Server is working!";
                [self performSelectorOnMainThread:@selector(showMessageBoxWithString:) withObject:messageToShow waitUntilDone:YES];
                [self performSelectorOnMainThread:@selector(threadedUIActivityRemover:) withObject:nil waitUntilDone:YES];
            }else
            {
                messageToShow = @"Server is NOT working!";
                [self performSelectorOnMainThread:@selector(showMessageBoxWithString:) withObject:messageToShow waitUntilDone:YES];
                [self performSelectorOnMainThread:@selector(threadedUIActivityRemover:) withObject:nil waitUntilDone:YES];
            }
        }

    });

    dispatch_release(testServer);
}

-(void)threadedUIActivityRemover:(NSString *)string
{
    [self.imageView setHidden:NO];
    [self.activityView setHidden:YES];
    [self.activityView stopAnimating];
}

Is this a good way of doing this, is there anything besides performSelectorOnMainThread this you can point me to, that works better?

As you can see I pass nil to an NSString argument in this example, because I HAVE to pass something, if I don't have NSString as an arg in the method, the app crashes evan when passing nil.. Why is this?.. please make this a bit clearer for me!

//Thanks!

Catiline answered 29/8, 2011 at 16:30 Comment(0)
E
10

Well, you're already using dispatch_async. Then you should just use

     dispatch_async(dispatch_get_main_queue(),^ { ... } );

from inside your background thread to perform things on the main thread. For example,

     if ([self testServerMethod])
        {
            dispatch_async(dispatch_get_main_queue(),^ {
               [self showMessageBoxWithString: @"Server is working!"];
               [self threadedUIActivityRemover:nil];
            } );
        }else ...

It doesn't have any constraint on the number of arguments for the methods you call.

Elga answered 29/8, 2011 at 16:40 Comment(4)
This worked liked a charm and was EXACLY what I was requesting.. performSelectorOnMainThread seemed a little bit to constraint to me! This is great.. Is there anything I should be careful about when switching between threads this way? is there any time I shouldn't use async etc.?Catiline
You know, in the olden days we only had detachNewThreadSelector and performSelectorOnMainThread. Now we have dispatch_* and NSOperationQueue. Everything is easier now. Usually async just works, if you don't have to do anything in the background thread after you update the UI.Elga
ok, glad I'm not from the olden days then =). this seems to work very smoothly. Thanks a bunch for the help! I'll read some documentation get a better understanding of how dispatch_* works.. Thanks!Catiline
i had problems using dispatch_async(dispatch_get_main_queue() ( never worked out exactly why ) but the UI would hang, but it worked with performSelectorOnMainThreadPyrope
O
2

Pass a collection, such as a dictionary of unarchived objects.

Originative answered 29/8, 2011 at 16:41 Comment(2)
Yes, I can do that.. But, it seems.. weird. Why can't there be a performSelectorOnMainThread without having to pass anything.. One more thing. I can't perform a selector on my delegate from this method either.. I have to call a method in self. This also means that I have to write a lot of methods for just this. Methods that only are there to be called from this method.Catiline
you can pass nil as an argument to performSelectorOnMainThread - if the app crashes, it's not a result of the implementation in Foundation.framework.Originative
O
1

You can also use an NSInvocation.

Originative answered 29/8, 2011 at 16:43 Comment(1)
GIYF - this was one of the top results: #2964433Originative
O
0

since you are passing instance variables, another option would be to pass self and make self thread safe.

Originative answered 29/8, 2011 at 16:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.