Keeping a timer running on another page when navig

2019-05-21 12:02发布

问题:

I'm trying to keep a timer running on another page when you switch to other pages and complete other tasks, in essence keeping a clock on how long it takes to do the tasks. Whenever I switch to another page, it resets the timer back to what it was started, and does the same with some switches on other pages that I'm trying to keep on. Any ideas?

Screenshot of storyboards:

Code so far:

//
//  ViewController.m


#import "ViewController.h"

@interface ViewController ()


@end

@implementation ViewController

- (IBAction)start{
ticker = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self    ``selector:@selector(showActivity) userInfo:nil repeats:YES];

}

- (IBAction)reset{
[ticker invalidate];
time.text = @" 0:00";
}

- (void)showActivity{
int currentTime = [time.text intValue];
int newTime = currentTime + 1;
time.text = [NSString stringWithFormat:@"%d", newTime];
}




- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end

//  ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController{

IBOutlet UILabel *time;
NSTimer *ticker;
}

- (IBAction)start;
- (IBAction)reset;


- (void)showActivity;
@end

回答1:

Your NSTimer is a member variable of your view controller class. I'm assuming that when you switch between views, you're destroying this view controller and instantiating an instance of a new one. That means this view controller is gone, as well as the timer; it's not that the timer is being reset, it's that your old timer has been destroyed an a new one is being created.

What you need is to store your NSTimer and its functionality in a place where it will not be destroyed every time you change your view controller. One solution is to create a Singleton class which handles the timer. (A Singleton class is a class that can only be created one time; only one instance of it can exist. You can read more about them here.)

Here is an example of how you can create a Singleton class in Objective-C. The header:

//ApplicationManager.h

@interface ApplicationManager : NSObject

+(ApplicationManager*) instance;

@end

And the implementation:

//ApplicationManager.m

#import "ApplicationManager.h"

@implementation ApplicationManager
static ApplicationManager* appMgr = nil;

+(ApplicationManager*) instance
{
    @synchronized([ApplicationManager class])
    {
        if(!appMgr)
        {
            appMgr = [[self alloc] init];
        }

        return appMgr;
    }

    return nil;
}    

+(id) alloc
{
    @synchronized([ApplicationManager class])
    {
        NSAssert((appMgr == nil), @"Only one instance of singleton class may be instantiated.");
        appMgr = [super alloc];
        return appMgr;
    }
}

-(id) init
{
    if(!(self = [super init]))
    {
        [self release];
        return nil;
    }

    return self;
}

@end

The first time you call the instance method, the instance of the ApplicationManager will be created. Each time you want to access it, call the instance method again; the ApplicationManager will be returned. Now you simply add your NSTimer (and any other object you wish to persist throughout your application) as member variables of the ApplicationManager class.

You then must import the ApplicationManager class into your view controller class, and your view controller methods will change to:

-(IBAction) start
{
    [[ApplicationManager instance] setTicker:[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(showActivity) userInfo:nil repeats:YES]];
}

-(IBAction) reset
{
    [[[ApplicationManager instance] ticker] invalidate];
    time.text = @" 0:00";
}

-(void) showActivity
{
    int currentTime = [time.text intValue];
    int newTime = currentTime + 1;
    time.text = [NSString stringWithFormat:@"%d", newTime];
}

If you want to make things nice and neat, you can also add this line to the top of your ApplicationManager class:

#define APPMGR [ApplicationManager instance]

Now instead of having to type [ApplicationManager instance] everywhere, you can simply refer to it as APPMGR instead. [APPMGR ticker] is a lot cleaner than [[ApplicationManager instance] ticker] :)