4

I know how to use NSDate to get the time and display it inside UILabel.

i need to display the date + hours and minutes. any idea how can i keep it updated without busy-waiting?

Thanks!

Chiko
  • 606
  • 9
  • 21
  • [currentDate description] will give me the current time but i don't want to keep asking for it all the time... – Chiko Mar 17 '13 at 10:23

4 Answers4

6

Use NSTimer to update time on the label

- (void)viewDidLoad
 {
  [super viewDidLoad];

   [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTime) userInfo:nil repeats:YES];
 }



-(void)updateTime
{


NSDate *date= [NSDate date];
NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init]; //for hour and minute

formatter1.dateFormat = @"hh:mm a";// use any format 

clockLabel.text = [formatter1 stringFromDate:date];

[formatter1 release];


}
Anil Varghese
  • 42,757
  • 9
  • 93
  • 110
  • as i wrote before - that's exactly what i was trying to avoid. i thought about maybe listen to some notification that is fired every time the minutes changes? – Chiko Mar 17 '13 at 10:29
  • There is no such notification. If you need something to happen periodically -- like a label's text changing -- you use a timer. – jscs Mar 17 '13 at 14:08
2

As your comments said , if you want when minutes changes you change the label.text

you should do like this :

1st: get the current time:

NSDate *date = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [calendar components:NSHourCalendarUnit fromDate:date];

and set the label.text = CURRENTHOUR_AND_YOURMINNUTS;

and then refresh the label next minute,like this :

the first , you can check after 60 - nowSeconds [self performSelector:@selector(refreshLabel) withObject:nil afterDelay:(60 - dateComponents.minute)];

- (void)refreshLabel
{
    //refresh the label.text on the main thread
    dispatch_async(dispatch_get_main_queue(),^{      label.text = CURRENT_HOUR_AND_MINUTES;    });
    // check every 60s
    [self performSelector:@selector(refreshLabel) withObject:nil afterDelay:60];
}

It will check every minute , so the effecent is more than answers above.

When refreshLabel invocated , it means the minutes changed

Guo Luchuan
  • 4,729
  • 25
  • 33
  • `performSelector:afterDelay:` is not more efficient than a timer, and this solution is needlessly convoluted. – jscs Mar 17 '13 at 14:13
  • @JoshCaswell you did not see my answer carefully. He want refresh the label every minute. so I invocate the refresh the label , every 60s , they refresh every 1s , so I said my answer is more efficient – Guo Luchuan Mar 17 '13 at 14:40
  • I didn't understand that difference, you're right, but in fact it's best to check the time at a smaller interval than what you actually want to display, because neither an NSTimer nor `performSelector:afterDelay:` is guaranteed to fire at exactly the set time. You also don't need the bit with the main queue, or the `NSDateComponents`, and it's not at all clear what `CURRENTHOUR_AND_YOURMINNUTS;` is supposed to be. – jscs Mar 17 '13 at 14:50
  • @JoshCaswell. the`NSDateComponents` is to get the hour and the minute(via `dateComponents.hour` and `dateComponents.minute` ) , because he want to show the hour and the minute, I do not what format he want so I use `CURRENTHOUR_AND_YOURMINNUTS ` . And refresh the UI(label.text) can not use main thread ? – Guo Luchuan Mar 17 '13 at 14:55
  • You're not on a background thread before that, and you should use a formatter to do formatting. – jscs Mar 17 '13 at 15:00
  • @JoshCaswell yes your are right , may be not in background. `performSelector:afterDelay ` is run in `current thread` , `current thread` maybe is main thread or background thread , we do not have context code , so I used `dispatch_get_main_queue()`. And why I did not use formatting , because I should use seconds , the minute and the hour , it is adviced to do like mine , you can see this :http://stackoverflow.com/questions/15019583/how-to-check-whether-now-date-is-during-900-1800/15020985#15020985 – Guo Luchuan Mar 17 '13 at 15:12
  • @JoshCaswell thankyou for your advice , but I have to sleep , be happy to discuss with you tomorrow – Guo Luchuan Mar 17 '13 at 15:14
  • That answer is for doing calculations with dates, not displaying them to a user. Formatting things for display is _exactly_ what formatters are for. Code doesn't just run on other threads at random. Only if you put it there. – jscs Mar 17 '13 at 16:03
1

You can use the NSTimer to periodically get the current time.

[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(timerFired:) userInfo:nil repeats:YES];

- (void)timerFired:(NSTimer*)theTimer{
 //you can update the UILabel here.
}
lu yuan
  • 7,207
  • 9
  • 44
  • 78
  • that's exactly what i was trying to avoid... can't i listen to some notification that is fired every time the minutes changes? – Chiko Mar 17 '13 at 10:25
  • 1
    @user1369740 As far as I know, there isn't such notification. – lu yuan Mar 17 '13 at 10:40
-1

You can use NSTimer , but , given the above methods , the UILabel won't update on touch Events as the main thread will be busy tracking it.You need to add it to mainRunLOOP

    NSTimer* timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(updateLabelWithDate) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

-(void)updateLabelWithDate
{
   //Update your Label
}

You can change the time interval(rate at which you want Updation).

Abhishek Singh
  • 6,068
  • 1
  • 23
  • 25
  • When a timer is created with `scheduledTimer...` it is already added to the run loop. This is unnecessary. – jscs Mar 17 '13 at 14:10