上一篇文章写了一个简单的定时器,也可以正常的运行了。但是现在有一个问题,就是如果像我们手机上那个定时器程序一样。即使切换到闹钟或者世界时间的时候定时器依然要要在后在运行。我们刚才那种写法就并不行了。因为我们当我们转换其他界面的时候,已经退出了那个定时器的界面,意味着那个界面的Controller已经被销毁了。我们的定时器并不能在我们切换到其他界面的时候依然运行。这个时候需要一个怎样的方法来解决啦。我们就要用到一个在很多语言下都有的模式叫单例模式。
首先最重要的问题时搞懂什么叫做单例模式。在网上查了很多资料,都看的不是很懂,现在我说一下我自己的理解。单例是一个跟程序的运行的周期一样的类。一个程序里面只能有一个单例类的实例。你现在有个controller,你在里面实例化了一个单例,你在这个controller中修改了这个实例的属性的值。现在有另外一个controller1。你在这个类中继续实例化了一个单例。你查看这个实例属性的值,你会发现跟刚才你修改过后的属性的值一样。而且单例生命周期是跟程序生命周期一样,所以当你退出了那个界面之后 你会发现定时器依然在后台运行。
所以我们想使定时器在我们退出那个界面之后还能继续运行,我们就需要创造一个单例类。
下面贴出单例类的代码
Timemanager.h 文件
class="p1">#import <Foundation/Foundation.h>
#import "Time.h"
@interface Timemanage : NSObject
@property(nonatomic,strong) Time *time;
+(Timemanage*)shareManage;//单例类的类初始化方法,十分重要,决定了你这个类是否是单例类
-(void)timestart;
-(void)timepause;
@end
Timemanage.m文件
#import "Timemanage.h"
@interface Timemanage()
@property(nonatomic,retain)NSTimer *timer;
@end
@implementation Timemanage
+(Timemanage*)shareManage;//单例的初始化方法,有很多种,但是这个是苹果官方推荐的。
{
static Timemanage *timemanageInstance=nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
timemanageInstance=[[self alloc]init];
});
return timemanageInstance;
}
-(void)timestart
{
if (!_timer) {
_timer=[NSTimer scheduledTimerWithTimeInterval:0.01f target:self selector:@selector(UpdateUI) userInfo:nil repeats:YES];
}
}
-(void)timepause
{
if (_timer.valid) {
[_timer invalidate];
}
_timer=nil;
}
-(void)UpdateUI
{
self.time.ms++;
[self.time changtime];
// [self.changedelegate changeUIwithtimestring:[self.time timestring]];会使用到的协议
}
-(Time*)time
{
if (!_time) {
_time=[[Time alloc]init];
}
return _time;
}
@end
我们要的单例已经创建成功了。但是现在问题是怎么才能把我们的时间实时同步到我们的UI上面,刚才没用到单例的时候,我们可以直接在controller中初始化我们的NSTimer,并且在在UPdateUI方法中实时更新我们的UI,但是现在我们并不能直接引用lable了。所以在这里我们必须使用协议以保证我们的UI与数据同步。
首先修改下我们的Timemanage.h文件,在这个文件中创建我们的协议
#import <Foundation/Foundation.h>
#import "Time.h"
@protocol changeUIdelegate <NSObject>
-(void)changeUIwithtimestring:(NSString*)time;//创建协议
@end
@interface Timemanage : NSObject
@property(nonatomic,strong) Time *time;
@property(nonatomic,retain) id<changeUIdelegate> changedelegate;//设置协议
+(Timemanage*)shareManage;
-(void)timestart;
-(void)timepause;
@end
现在只需要在Timemanage.m中添加一句话
把UpdateUI方法修改一下
-(void)UpdateUI
{
self.time.ms++;
[self.time changtime];
[self.changedelegate changeUIwithtimestring:[self.time timestring]];//委托,这个方法调用的时候,viewcontroller的实现协议的方法也会调用。
}
贴一下viewcontroller的代码
#import "ViewController.h"
#import "Timemanage.h"
@interface ViewController ()<changeUIdelegate>//声明实现了协议
@property (weak, nonatomic) IBOutlet UILabel *lable;
@property(strong,nonatomic) Timemanage *time;
@end
@implementation ViewController
- (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.
}
- (IBAction)start:(id)sender {
_time=[Timemanage shareManage];
_time.changedelegate=self;//把委托对象设为自己
[_time timestart];
}
-(void)changeUIwithtimestring:(NSString *)time
{
self.lable.text=time;//协议的实现,将传过来的time显示在lable。
}
- (IBAction)stop:(id)sender {
[_time timepause];
}
现在大家可以添加个viewtroller2,然后切换到另外一个界面,再切换到计时器页面,会发现计时器依然在运行。
第一次写博客,有很多东西表达不是很清楚。希望能指出。
@end