39

I am unable to change the UILabel text. The code for the the UILabel inside viewDidLoad is :

startLabel=[[UILabel alloc] initWithFrame:CGRectMake(75, 395, 200, 30)];
startLabel.text=@"Recording Sound ...";
startLabel.backgroundColor=[UIColor clearColor];
startLabel.textColor=[UIColor whiteColor];
startLabel.font=[UIFont boldSystemFontOfSize:17];

[self.view addSubview:startLabel];

Later, if I want to change the label of the text with the following code, its not changing on the app :

startLabel.text=@"Searching Database ...";

or

[startLabel setText:@"Searching Database ..."];

The UILabel is not empty, I printed it out during debugging and it shows :

(gdb) po startLabel
<UILabel: 0x2c1a30; frame = (75 395; 200 30); text = 'Searching Database ...'; 
clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x2ae8f0>>

So, the text of the label changes inside the UILabel, but its not updated on the screen.

Can anyone kindly let me know what I am missing here ? Thanks.

Edit 1: I tried performSelectorOnMainThread: - didnt work for me. Edit 2: I am using AVFoundation and ASIHTTP classes to record sound and upload the recorded file here. Nothing else. Didnt use any thread.

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
Ahsan
  • 2,964
  • 11
  • 53
  • 96
  • Where are you updating the text (what method)? It needs to be on the same thread (see: http://stackoverflow.com/questions/6000741/cant-redraw-uilabel-after-updating-text). – Ben Jakuben Jul 26 '11 at 19:39
  • @Ben : aint that for monotouch ? Also, I am inside the same thread, just another function ! – Ahsan Jul 26 '11 at 19:42
  • I totally missed that being a MonoTouch question, but I found a similar issue about needing to be on the same thread in a Mac forum that used performSelectorOnMainThread (http://forums.macrumors.com/showthread.php?t=463200), so I just wondered where you were calling it from. – Ben Jakuben Jul 26 '11 at 19:57
  • @Ben : nope..not working.. :(.. any other suggestions ? – Ahsan Jul 26 '11 at 20:26

5 Answers5

50

In my case the function that was updating was called from a touch recognizer on a thread, but the place in the function where I'm changing the value of the label's text property I put it back on the main thread:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.someLabel setText:someString];
});
ndoc
  • 907
  • 8
  • 6
50

You may be facing an issue with threading as mentioned in the comments above. If you have a method that runs on the main thread and does some activity (such as search a database), updates that you make to the UI will not be committed until the run loop gets control. So, if you have a long, time consuming task going on on the main thread, run this code after setting the text of the label:

- (void)doSomethingTimeConsuming
    ... consume some time ...
    ... set text of label ...
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
    ... continue long operation ...
}

This should flush out any UI changes that you have made. Although this may be a sensible and functional hack, it doesn't beat the alternative. I highly suggest that you perform your app's time consuming tasks on a background thread, and update the UI through the main thread using performSelectorOnMainThread:withObject:waitUntilDone:. See Apple's page on iOS Thread Management.

Alex Nichol
  • 7,512
  • 4
  • 32
  • 30
  • Thanks for the suggestion. Here's what I am doing inside the app/view. I am using AVFoundation to record some sound and using ASIHTTP class to upload the recorded sound. nothing special.... In the function that uploads the file (a custom function) , I am initially writing the code to change the label. Nothing works. I even tried performSelectorOnMainThread ...didnt work. Do you think the recording/uploading qualifies as a separate thread ? Please suggest what I can do. Thanks. – Ahsan Jul 27 '11 at 21:34
  • 1
    [[NSRunLoop mainRunLoop] .. thingy worked.... the other alternate didnt... thanks a bunch.. :) you just made my day ! – Ahsan Jul 27 '11 at 23:46
  • 1
    Thanks, I was having a similar problem but the `performSelectorOnMainThread:withObject:waitUntilDone:` solution worked great for me. Traced back the problem to the fact that a UI update was getting triggered (but not showing up) from a code block that was set to run after an asynchronous URL request finished. I might even suggest making that solution appear more prominently in your answer so that people don't miss it, as it's currently the accepted answer? – Matt May 16 '14 at 01:27
  • even `[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0]];` works for me (with 0 timeinterval) – dollar2048 Jun 08 '17 at 20:31
5

I had a UILabel showing a level number that would not update to the new level number on a UIViewController. The only viable solution I could find that worked was to call setNeedsDisplay on the main thread of the view controller that owned the UILabel

-(void)changeLevelLabel:(int)theLevel {
dispatch_async(dispatch_get_main_queue(), ^{
    self.levelLabel.text = [NSString stringWithFormat:@"%d",theLevel];
    [self.levelLabel setNeedsDisplay];
});

}

See http://iosdevelopmentjournal.com/blog/2013/01/16/forcing-things-to-run-on-the-main-thread/ for a more detailed explanation

user1233894
  • 1,582
  • 1
  • 11
  • 10
3

Mine's a bit more unexpected, though reasonable--just not something anyone thinks too hard about.

I'm supposed to update the UILabel when I receive an NSNotification that I fired somewhere else. However, the notification was fired from a background thread so even the listener methods that update the label's text are fired in the background.

If you're relying on an NSNotification to update the label, or any of your views, do fire the NSNotification from the main UI thread.

Matthew Quiros
  • 13,385
  • 12
  • 87
  • 132
0

In case you are using localize-Swift cocoapod, If you set a localized key to the UILabel, The value will be set after you set any text to the label.

Li Jin
  • 1,879
  • 2
  • 16
  • 23