1

I read some informations that UI interface only update on MainThread.

I need to asynchronous update some UIButtons, so I use performSelectorInBackground and it's work fine on simulator and Device (iPad4).

[self performSelectorInBackground:@selector(toggleToUpperWhenSingleShift) withObject:nil];

- (void)toggleToUpperWhenSingleShift{
    shiftStateIndicator = 1;
    for (UIView *aPad in self.subviews) {
        if ( [aPad isKindOfClass:[UIButton class]] ) {
            UIButton *aButPad = (UIButton *)aPad;
            NSMutableString *currentTitle = [NSMutableString stringWithString:[aButPad titleForState:UIControlStateNormal]];
            NSString *firstChar = [currentTitle substringToIndex:1];
            [currentTitle replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar uppercaseString]];
            [aButPad setTitle:currentTitle forState:UIControlStateNormal];
            [aButPad setTitle:currentTitle forState:UIControlStateHighlighted];

            currentTitle = [NSMutableString stringWithString:[aButPad titleForState:UIControlStateSelected]];
            firstChar = [currentTitle substringToIndex:1];
            [currentTitle replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar uppercaseString]];
            [aButPad setTitle:currentTitle forState:UIControlStateSelected];
        }
    }
}

I'm worried some unwanted functions will happen if I keep my code. Can anyone explain me detail about performSelectorInBackground?

Why not use it to update UI and why it's OK with my app? Anyway to debug problem will appreciate!

LE SANG
  • 10,955
  • 7
  • 59
  • 78
  • What do you mean with *I need to asynchronous update some UIButtons*? Below the link to UIView docs (read **Threading Considerations**) http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIView_Class/UIView/UIView.html – Lorenzo B Apr 01 '13 at 09:16
  • performSelectorInBackground is asynchronous with normal method. Am I understand wrong? – LE SANG Apr 01 '13 at 09:19
  • 2
    Read the following discussion http://stackoverflow.com/questions/11122957/is-it-ok-to-create-a-uiview-on-a-background-thread. `performSelectorInBackground` it's a sync method. It means the code within it will be performed in a serial fashion. But in a different thread. An async pattern is the one used by async `NSURLConnection`, for example. – Lorenzo B Apr 01 '13 at 09:24
  • Thanks! I mis-understand that different thread is async. – LE SANG Apr 01 '13 at 09:27

3 Answers3

7

performSelectorInBackground: is almost never what you want, for almost anything (and certainly not since the creation of GCD). It creates a new thread that you have little control over. That thread will run for as long as the method you dispatch to it.

By "little control" what I mean is that you don't get an NSThread object back, so it is very easy to accidentally call this method many times and fork an unbounded number of threads. I've seen this happen in several programs.

In iOS, you should almost never manually create a thread. GCD and NSOperation handle almost everything that manual threads could do, but better. You typically want thread pooling so you don't spin up and spin down threads all the time. GCD gives you that. You want to cap how many threads you create so you don't overwhelm the processor. GCD gives you that. You want to be able to prioritize your background actions easily. GCD gives you that, too.

All that said, I can't figure out why you're trying to do the above operation on a background thread. Almost all the work is UI updates. You must never, ever, try to modify the UI on a background thread. It is undefined behavior, and when it goes wrong, it goes very wrong. The fact that it's worked in a few cases means nothing. UIKit is not thread safe. You should just call toggleToUpperWhenSingleShift on the main thread. I don't see anything in that should block you, and the overhead of context switching to a background thread really isn't worth it here (even if it were safe, which it's not).

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
3

Making UI changes in a background thread is highly advised against by Apple.

You should either use performSelectorOnMainThread or send a message to the UI thread's dispatch queue and do your UI modifications from there.

dispatch_async(dispatch_get_main_queue(), ^{
  // your code here
});
lostInTransit
  • 70,519
  • 61
  • 198
  • 274
0

It is strongly recommended not to update UI controls etc from a background thread (e.g. a timer, comms etc). This can be the cause of crashes which are sometimes very hard to identify. Instead use these to force code to be executed on the UI thread (which is always the “main” thread).

Go to http://www.ios-developer.net/iphone-ipad-programmer/development/threads/updating-ui-controls-on-background-threads

for further reading.

bpolat
  • 3,879
  • 20
  • 26
  • 1
    Note that timers are generally not run on background threads. `NSTimer` in particular is generally run on the main thread, and is fine for UI updates. I don't know what you mean by "comms" but note that `NSURLConnection` callbacks are also generally on the main thread. But you're correct that you should never update UI controls on a backgroung thread. – Rob Napier Apr 04 '13 at 01:11