cell中使用定时器

cell 中使用定时器的小探索

需求

最近有一个需求,是需要在 cell 中开启定时器,并且更新计时时间。
需求并不复杂,涉及到如何封装定时器的问题。在网上看了一些例子,觉得和控制器的耦合太严重了,自己实现了一个。

设计

由于每个 cell 只是负责 UI 的显示,所以并不需要关心定时器的逻辑,而控制器的复用性太差,所以将定时器的逻辑写在 模型 中最为合适。可以为 模型 创建一个计时的分类。使用objc_setAssociatedObject 关联属性,创建一个定时器,添加定时器的开启和关闭方法。并定时以 block的形式将计时开始的时间返回出来,更新 UI 的显示。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#import "ViewController.h"
@interface TimerObj : NSObject
@property (nonatomic, strong) NSTimer *timer; /**< 定时器*/
@property (nonatomic, strong) NSDate *start; /**< 实际开始时间,用于定时器计算*/
@property (nonatomic, strong) NSDate *end; /**< 结束计时时间*/
@property (nonatomic, copy) void(^didChangeTime)(NSDate *date);
- (void)fire;
- (void)invalid;
- (BOOL)isCounting;
@end
@implementation TimerObj
- (void)fire {
if (_timer.isValid) {
[_timer invalidate];
}
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateDate) userInfo:nil repeats:YES] ;
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
_start = [NSDate new];
[_timer fire];
}
- (void)invalid {
[_timer invalidate];
_end = [NSDate new];
}
- (BOOL)isCounting {
return _start && !_end;
}
- (void)updateDate {
if (self.didChangeTime) {
self.didChangeTime(self.start);
}
}
@end
@interface RootViewController ()
@property (nonatomic, strong) NSArray *list;
@end
@implementation RootViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self configureUI];
[self testDate];
}
- (void)configureUI {
self.view.backgroundColor = [UIColor lightGrayColor];
self.tableView.tableFooterView = [UIView new];
self.title = @"Timer Test";
}
- (void)testDate {
NSMutableArray *mAry = [NSMutableArray array];
for (NSInteger i = 0; i < 10; i++) {
[mAry addObject:[TimerObj new]];
}
_list = [NSArray arrayWithArray:mAry];
}
#pragma mark - table view delegete & datasource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _list.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = @"identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
}
TimerObj *obj = _list[indexPath.row];
obj.didChangeTime = ^(NSDate *date) {
CGFloat now = [NSDate new].timeIntervalSince1970 - date.timeIntervalSince1970;
cell.textLabel.text = [NSString stringWithFormat:@"%.2f", now];
};
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
TimerObj *obj = _list[indexPath.row];
if (obj.isCounting) {
[obj invalid];
} else {
[obj fire];
}
}
@end