UILabel Not Updating When Returning to UIViewController

匿名 (未验证) 提交于 2019-12-03 08:30:34

问题:

I have a simple app that has an NSTimer object in the appDelegate to be accessed by all views. The structure of the app is with a UINavigationController. When I fire the NSTimer object, my UILabel is being updated with the correct countdown function, but when I go back to the rootViewController and back to the countdown timer view, my UILabel is being updated with the current countdown time, but no subsequent updates to the UILabel happen. What am I missing? I have done research on making sure the UILabel object is not nil, that I call the function on the viewDidAppear method, and nothing seems to work! Here is the code:

AppDelegate.h

@interface AppDelegate : UIResponder <UIApplicationDelegate> { } @property (nonatomic, retain) NSTimer *countdownTimer; 

AppDelegate.m

@implementation AppDelegate  @synthesize countdownTimer; 

CountdownTimerViewController.h

#import "AppDelegate.h" enter code here @interface CountdownTimerViewController : UIViewController { enter code here AppDelegate *appdelegate;  }  @property (strong, nonatomic) IBOutlet UILabel *labelCountdownTimer; @property (strong, nonatomic) IBOutlet UIButton *buttonStartTimer; @property (strong, nonatomic) IBOutlet UIButton *buttonStopTimer;  - (IBAction)startTimer:(id)sender; - (IBAction)stopTimer:(id)sender; 

CountdownTimerViewController.m

@implementation CountdownTimerViewController  @synthesize labelCountdownTimer;  - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];     if (self) {         // Custom initialization     }     return self; }  - (void)viewDidLoad {     [super viewDidLoad];     // Do any additional setup after loading the view.      //Instatiating Appdelegate     if(!appdelegate)         appdelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];  }  - (void) viewDidAppear:(BOOL)animated {      if ([appdelegate.countdownTimer isValid]) {         [self countDown];     }  }  - (void)didReceiveMemoryWarning {     [super didReceiveMemoryWarning];     // Dispose of any resources that can be recreated. }  #pragma mark - Button Action Methods  - (IBAction)startTimer:(id)sender {      [self updateCounter];  }  - (IBAction)stopTimer:(id)sender {      [appdelegate.countdownTimer invalidate];     labelCountdownTimer.text = @"00:00:00";  }  int countLimit=30; //seconds NSDate *startDate;  - (void)countDown {      if([[NSDate date] timeIntervalSinceDate:startDate] >= countLimit) {         [appdelegate.countdownTimer invalidate];         return;     }     else {                 NSDate *currentDate = [NSDate date];     NSTimeInterval timeInterval = -([currentDate timeIntervalSinceDate:startDate]);     NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];     NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];     [dateFormatter setDateFormat:@"mm:ss"];     [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];     NSString *timeString = [dateFormatter stringFromDate:timerDate];         NSLog(@"timeString: %@",timeString);         NSLog(@"labelCountdownTimer: %@",labelCountdownTimer);     labelCountdownTimer.text = timeString;     }  }  - (void)updateCounter {      labelCountdownTimer.text = @"00:00:00";     startDate = [NSDate date];      appdelegate.countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0                                                                   target:self                                                                 selector:@selector(countDown)                                                                 userInfo:nil                                                                  repeats:YES];  } 

回答1:

Thanks to everyone for your comments. I actually solved it by performing a method that will go and retrieve the value that the NSTimer is updating in my AppDelegate, since the method firing the NSTimer is no longer in the main thread when I leave the view and come back to it. This method will loop as long as my NSTimer is valid. I also placed a delay, allowing for the UI to update the value, and then perform the method again. Here is the code in case it helps someone running into a similar issue. I got this idea from the suggestion provided by chandan, thanks!!

AppDelegate.h

@interface AppDelegate : UIResponder <UIApplicationDelegate> {  }  @property (nonatomic, retain) NSTimer *countdownTimer; @property (nonatomic, retain) NSString *timeString; 

AppDelegate.m

@interface AppDelegate : UIResponder <UIApplicationDelegate> {  }  @property (nonatomic, retain) NSTimer *countdownTimer; @property (nonatomic, retain) NSString *timeString; 

CountdownTimerViewController.h

@interface CountdownTimerViewController : UIViewController {  AppDelegate *appdelegate;  }  @property (strong, nonatomic) IBOutlet UILabel *labelCountdownTimer;  @property (strong, nonatomic) IBOutlet UIButton *buttonStartTimer; @property (strong, nonatomic) IBOutlet UIButton *buttonStopTimer;  - (IBAction)startTimer:(id)sender; - (IBAction)stopTimer:(id)sender; 

CountdownTimerViewController.m

@implementation CountdownTimerViewController  @synthesize labelCountdownTimer;  - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];     if (self) {         // Custom initialization     }     return self; }  - (void)viewDidLoad {     [super viewDidLoad];         // Do any additional setup after loading the view.      //Instatiating Appdelegate     if(!appdelegate)         appdelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];  }  - (void) viewDidAppear:(BOOL)animated {      if ([appdelegate.countdownTimer isValid]) {         [self updateLabel];     } else {         labelCountdownTimer.text = @"00:00:00";     }  }  - (void)didReceiveMemoryWarning {     [super didReceiveMemoryWarning];     // Dispose of any resources that can be recreated. }  #pragma mark - Button Action Methods  - (IBAction)startTimer:(id)sender {      [self updateCounter];  }  - (IBAction)stopTimer:(id)sender {      [appdelegate.countdownTimer invalidate];     labelCountdownTimer.text = @"00:00:00";  }  int countLimit=30; //seconds NSDate *startDate;  - (void)updateCounter {      labelCountdownTimer.text = @"00:00:00";     startDate = [NSDate date];      appdelegate.countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0                                                                   target:self                                                                 selector:@selector(countDown)                                                                 userInfo:nil                                                                  repeats:YES];  }    - (void)countDown {      if([[NSDate date] timeIntervalSinceDate:startDate] >= countLimit) {         [appdelegate.countdownTimer invalidate];         return;     }     else {                 NSDate *currentDate = [NSDate date];     NSTimeInterval timeInterval = -([currentDate timeIntervalSinceDate:startDate]);     NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];     NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];     [dateFormatter setDateFormat:@"mm:ss"];     [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];     appdelegate.timeString = [dateFormatter stringFromDate:timerDate];     labelCountdownTimer.text = appdelegate.timeString;     }  }    - (void) updateLabel {      if ([appdelegate.countdownTimer isValid]) {         labelCountdownTimer.text = appdelegate.timeString;         [self performSelector:@selector(updateLabel) withObject:nil afterDelay:0.05];     }   } 


回答2:

Type casting like this:

appdelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 

won't actually make the UIApplicationDelegate into your AppDelegate class and add your extra parameters. Hence there will be no pointer to the timer in this variable.

You need a different approach for storing the timer pointer.



回答3:

Try to update text on UILabel on main thread. Sometimes updation in UILabel not working on backgound thread.

- (void) viewDidAppear:(BOOL)animated  {      if ([appdelegate.countdownTimer isValid])       {           [self performSelectorOnMainThread:@selector(countDown) withObject:nil waitUntilDone:NO];      }  } 

If your appdelegate object is working fine and UILabel is being updated with the current countdown time, but no subsequent updates to the UILabel happen then apply UI changes on main thread like it

- (void)countDown {   [self performSelectorOnMainThread:@selector(changeCountDownValue) withObject:nil waitUntilDone:NO]; }  - (void)changeCountDownValue {     if([[NSDate date] timeIntervalSinceDate:startDate] >= countLimit) {         [appdelegate.countdownTimer invalidate];         return;     }     else {                 NSDate *currentDate = [NSDate date];     NSTimeInterval timeInterval = -([currentDate timeIntervalSinceDate:startDate]);     NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];     NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];     [dateFormatter setDateFormat:@"mm:ss"];     [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];     NSString *timeString = [dateFormatter stringFromDate:timerDate];         NSLog(@"timeString: %@",timeString);         NSLog(@"labelCountdownTimer: %@",labelCountdownTimer);     labelCountdownTimer.text = timeString;     }  } 

please double check with NSTimer object. It should be working fine for UILabel updation. Please let me know if any problem still occurring.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!