-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathSTNetTaskGroup.m
More file actions
190 lines (167 loc) · 5.83 KB
/
STNetTaskGroup.m
File metadata and controls
190 lines (167 loc) · 5.83 KB
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
//
// STNetTaskGroup.m
// STNetTaskQueue
//
// Created by Kevin Lin on 8/5/16.
// Copyright © 2016 Sth4Me. All rights reserved.
//
#import "STNetTaskGroup.h"
#import "STNetTaskQueue.h"
static NSMutableSet<STNetTaskGroup *> *_retainedGroups; // Retain group to make sure it won't be autoreleased.
@interface STNetTaskGroup ()
@property (nonatomic, strong) STNetTask *executingTask;
@property (nonatomic, strong) NSArray<STNetTask *> *tasks;
@property (nonatomic, assign) BOOL pending;
@property (nonatomic, assign) BOOL started;
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, NSMutableArray<STNetTaskGroupSubscriptionBlock> *> *stateToBlock;
@property (nonatomic, strong) STNetTaskSubscriptionBlock taskSubscriptionBlock; // For serial mode
@property (nonatomic, strong, readonly) STNetTaskQueue *queue;
@end
@implementation STNetTaskGroup
- (instancetype)initWithTasks:(NSArray<STNetTask *> *)tasks mode:(STNetTaskGroupMode)mode
{
return [self initWithTasks:tasks mode:mode queue:[STNetTaskQueue sharedQueue]];
}
- (instancetype)initWithTasks:(NSArray<STNetTask *> *)tasks mode:(STNetTaskGroupMode)mode queue:(STNetTaskQueue *)queue
{
if (self = [super init]) {
self.tasks = [NSArray arrayWithArray:tasks];
_mode = mode;
_queue = queue;
}
return self;
}
- (void)addTask:(STNetTask *)task
{
NSMutableArray *tasks = [_tasks mutableCopy];
[tasks addObject:task];
self.tasks = [NSArray arrayWithArray:tasks];
}
- (STNetTaskGroup *)subscribeState:(STNetTaskGroupState)state usingBlock:(STNetTaskGroupSubscriptionBlock)block
{
if (!self.stateToBlock) {
self.stateToBlock = [NSMutableDictionary new];
}
NSMutableArray *blocks = self.stateToBlock[@(state)];
if (!blocks) {
blocks = [NSMutableArray new];
self.stateToBlock[@(state)] = blocks;
}
[blocks addObject:[block copy]];
return self;
}
- (void)notifyState:(STNetTaskGroupState)state withError:(NSError *)error
{
NSMutableArray<STNetTaskGroupSubscriptionBlock> *blocks = self.stateToBlock[@(state)];
for (STNetTaskGroupSubscriptionBlock block in blocks) {
block(self, error);
}
self.stateToBlock = nil;
self.taskSubscriptionBlock = nil;
[_retainedGroups removeObject:self];
}
- (void)start
{
NSAssert(!self.started, @"STNetTaskGroup can not be reused, please create a new instance.");
if (self.pending) {
return;
}
self.pending = YES;
self.started = YES;
if (!_retainedGroups) {
_retainedGroups = [NSMutableSet new];
}
[_retainedGroups addObject:self];
switch (self.mode) {
case STNetTaskGroupModeSerial: {
__block NSUInteger executingTaskIndex = 0;
__weak STNetTaskGroup *weakSelf = self;
self.taskSubscriptionBlock = ^{
if (weakSelf.executingTask.error) {
[weakSelf notifyState:STNetTaskGroupStateFinished withError:weakSelf.executingTask.error];
return;
}
executingTaskIndex++;
if (executingTaskIndex == weakSelf.tasks.count) {
[weakSelf notifyState:STNetTaskGroupStateFinished withError:nil];
}
else {
weakSelf.executingTask = weakSelf.tasks[executingTaskIndex];
[weakSelf.queue addTask:weakSelf.executingTask];
[weakSelf.executingTask subscribeState:STNetTaskStateFinished usingBlock:weakSelf.taskSubscriptionBlock];
}
};
self.executingTask = self.tasks[executingTaskIndex];
[self.queue addTask:self.executingTask];
[self.executingTask subscribeState:STNetTaskStateFinished usingBlock:self.taskSubscriptionBlock];
}
break;
case STNetTaskGroupModeConcurrent: {
__block NSUInteger finishedTasksCount = 0;
for (STNetTask *task in self.tasks) {
[self.queue addTask:task];
[task subscribeState:STNetTaskStateFinished usingBlock:^{
if (task.error) {
[self cancelTasks];
[self notifyState:STNetTaskGroupStateFinished withError:task.error];
return;
}
finishedTasksCount++;
if (finishedTasksCount == self.tasks.count) {
[self notifyState:STNetTaskGroupStateFinished withError:nil];
}
}];
}
}
break;
default:
break;
}
}
- (void)cancel
{
if (!self.pending) {
return;
}
switch (self.mode) {
case STNetTaskGroupModeSerial: {
[self.queue cancelTask:self.executingTask];
self.executingTask = nil;
}
break;
case STNetTaskGroupModeConcurrent: {
[self cancelTasks];
}
break;
default:
break;
}
[self notifyState:STNetTaskGroupStateCancelled withError:nil];
}
- (void)cancelTasks
{
for (STNetTask *task in self.tasks) {
if (task.pending) {
[self.queue cancelTask:task];
}
}
}
@end
@implementation NSArray (STNetTaskGroup)
- (STNetTaskGroup *)serialNetTaskGroup
{
return [[STNetTaskGroup alloc] initWithTasks:self mode:STNetTaskGroupModeSerial];
}
- (STNetTaskGroup *)serialNetTaskGroupInQueue:(STNetTaskQueue *)queue
{
return [[STNetTaskGroup alloc] initWithTasks:self mode:STNetTaskGroupModeSerial queue:queue];
}
- (STNetTaskGroup *)concurrentNetTaskGroup
{
return [[STNetTaskGroup alloc] initWithTasks:self mode:STNetTaskGroupModeConcurrent];
}
- (STNetTaskGroup *)concurrentNetTaskGroupInQueue:(STNetTaskQueue *)queue
{
return [[STNetTaskGroup alloc] initWithTasks:self mode:STNetTaskGroupModeConcurrent queue:queue];
}
@end