你的位置:首页 > 操作系统

[操作系统]使用到定时器,单例和协议的一个小应用(2 )

    上一篇文章写了一个简单的定时器,也可以正常的运行了。但是现在有一个问题,就是如果像我们手机上那个定时器程序一样。即使切换到闹钟或者世界时间的时候定时器依然要要在后在运行。我们刚才那种写法就并不行了。因为我们当我们转换其他界面的时候,已经退出了那个定时器的界面,意味着那个界面的Controller已经被销毁了。我们的定时器并不能在我们切换到其他界面的时候依然运行。这个时候需要一个怎样的方法来解决啦。我们就要用到一个在很多语言下都有的模式叫单例模式。

    首先最重要的问题时搞懂什么叫做单例模式。在网上查了很多资料,都看的不是很懂,现在我说一下我自己的理解。单例是一个跟程序的运行的周期一样的类。一个程序里面只能有一个单例类的实例。你现在有个controller,你在里面实例化了一个单例,你在这个controller中修改了这个实例的属性的值。现在有另外一个controller1。你在这个类中继续实例化了一个单例。你查看这个实例属性的值,你会发现跟刚才你修改过后的属性的值一样。而且单例生命周期是跟程序生命周期一样,所以当你退出了那个界面之后 你会发现定时器依然在后台运行。

 

所以我们想使定时器在我们退出那个界面之后还能继续运行,我们就需要创造一个单例类。

下面贴出单例类的代码

Timemanager.h 文件

 

#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