forked from EFEducationFirstMobile/librabbitmq-objc
/
CTXTTLManager.m
158 lines (136 loc) · 5.4 KB
/
CTXTTLManager.m
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//
// CTXTTLManager.m
// SMARTClassroom
//
// Created by Pedro Gomes on 29/11/2012.
// Copyright (c) 2012 EF Education First. All rights reserved.
//
#import "CTXTTLManager.h"
#import <dispatch/source.h>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@interface CTXTTLManager()
- (void)_cancelTimerForObject:(id)object;
@end
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@implementation CTXTTLManager
{
dispatch_queue_t _lockQueue;
NSMutableArray *_objects;
NSMutableArray *_timers;
}
#pragma mark - Dealloc and Initialization
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
- (void)dealloc
{
[self _performCleanup];
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
- (id)initWithDelegate:(id<CTXTTLManagerDelegate>)delegate
{
if((self = [self init])) {
_delegate = delegate;
}
return self;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
- (id)init
{
if((self = [super init])) {
_lockQueue = dispatch_queue_create("com.ef.ctx.ttl-manager.lock", NULL);
_objects = [[NSMutableArray alloc] init];
_timers = [[NSMutableArray alloc] init];
}
return self;
}
#pragma mark - Public Methods
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
- (void)addObject:(id)object ttl:(NSTimeInterval)ttl
{
dispatch_sync(_lockQueue, ^{
// NSAssert([_objects indexOfObject:object] == NSNotFound, @"object %@ already exists", object);
if([_objects indexOfObject:object] != NSNotFound) {
return;
}
[_objects addObject:object];
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _lockQueue);
[_timers addObject:[NSValue valueWithPointer:timer]];
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, ttl * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0);
dispatch_source_set_event_handler(timer, ^{
[self _cancelTimerForObject:object];
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate ttlForObjectExpired:object];
});
});
dispatch_resume(timer);
});
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
- (BOOL)updateObject:(id)object ttl:(NSTimeInterval)ttl
{
__block BOOL updated = NO;
dispatch_sync(_lockQueue, ^{
NSUInteger indexOfObject = [_objects indexOfObject:object];
if(indexOfObject != NSNotFound) {
dispatch_source_t timer = [[_timers objectAtIndex:indexOfObject] pointerValue];
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, ttl * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0);
updated = YES;
}
});
return updated;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
- (void)removeObject:(id)object
{
dispatch_sync(_lockQueue, ^{
[self _cancelTimerForObject:object];
});
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
- (void)removeAllObjects
{
dispatch_sync(_lockQueue, ^{ @autoreleasepool {
NSArray *objectsToRemove = [NSArray arrayWithArray:_objects];
[objectsToRemove enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
[self _cancelTimerForObject:object];
}];
}
});
}
////////////////////////////////////////////////////////////////////////////////
// Needs to be wrapped with the appropriate locking mechanism
////////////////////////////////////////////////////////////////////////////////
- (void)_cancelTimerForObject:(id)object
{
NSUInteger indexOfObject = [_objects indexOfObject:object];
// NSAssert(indexOfObject != NSNotFound, @"object %@ does not exist", object);
if(indexOfObject == NSNotFound) {
return;
}
dispatch_source_t timer = [[_timers objectAtIndex:indexOfObject] pointerValue];
dispatch_source_cancel(timer);
[_objects removeObjectAtIndex:indexOfObject];
[_timers removeObjectAtIndex:indexOfObject];
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
- (void)_performCleanup
{
dispatch_sync(_lockQueue, ^{ @autoreleasepool {
[_timers enumerateObjectsUsingBlock:^(NSValue *timer, NSUInteger idx, BOOL *stop) {
dispatch_source_cancel([timer pointerValue]);
}];
[_timers removeAllObjects];
[_objects removeAllObjects];
}
});
}
@end