Skip to content

Commit 92f0359

Browse files
committed
1.0
1 parent 8ab1ac7 commit 92f0359

File tree

12 files changed

+206
-89
lines changed

12 files changed

+206
-89
lines changed

YBTaskScheduler.podspec

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
3+
Pod::Spec.new do |s|
4+
5+
6+
s.name = "YBTaskScheduler"
7+
s.version = "1.0"
8+
s.summary = "iOS 任务调度器,为 CPU 和内存减负"
9+
s.description = <<-DESC
10+
iOS 任务调度器,为 CPU 和内存减负
11+
DESC
12+
13+
s.homepage = "https://github.com/indulgeIn"
14+
15+
s.license = "MIT"
16+
17+
s.author = { "杨波" => "1106355439@qq.com" }
18+
19+
s.platform = :ios, "8.0"
20+
21+
s.source = { :git => "https://github.com/indulgeIn/YBTaskScheduler", :tag => "#{s.version}" }
22+
23+
s.source_files = "YBTaskScheduler/**/*.{h,m}"
24+
25+
s.requires_arc = true
26+
27+
end

YBTaskScheduler/YBTSPriorityQueue.mm

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,25 @@
1313

1414
using namespace std;
1515

16-
typedef pair<YBTaskBlock, NSInteger> YBTSPQTask;
16+
typedef struct YBTSPQTask {
17+
YBTaskBlock taskBlock;
18+
NSUInteger priority;
19+
CFTimeInterval time;
20+
} YBTSPQTask;
21+
22+
YBTSPQTask YBTSPQTaskMake(YBTaskBlock taskBlock, NSUInteger priority, CFTimeInterval time) {
23+
YBTSPQTask pqTask;
24+
pqTask.taskBlock = taskBlock;
25+
pqTask.priority = priority;
26+
pqTask.time = time;
27+
return pqTask;
28+
}
1729

1830
struct YBTSPQCMP {
1931
bool operator()(YBTSPQTask a, YBTSPQTask b) {
20-
return a.second < b.second;
32+
if (a.priority == b.priority)
33+
return a.time < b.time;
34+
return a.priority < b.priority;
2135
}
2236
};
2337

@@ -26,8 +40,6 @@ @implementation YBTSPriorityQueue {
2640
pthread_mutex_t _lock;
2741
}
2842

29-
@synthesize ybts_maxNumberOfTasks = _ybts_maxNumberOfTasks;
30-
3143
#pragma mark - life cycle
3244

3345
- (instancetype)init {
@@ -52,7 +64,7 @@ - (void)ybts_addTask:(YBTaskBlock)task priority:(YBTaskPriority)priority {
5264
if (!task) return;
5365

5466
pthread_mutex_lock(&_lock);
55-
_queue.push(make_pair(task, priority));
67+
_queue.push(YBTSPQTaskMake(task, priority, CFAbsoluteTimeGetCurrent()));
5668
pthread_mutex_unlock(&_lock);
5769
}
5870

@@ -63,7 +75,7 @@ - (void)ybts_executeTask {
6375
return;
6476
}
6577
YBTSPQTask pqTask = (YBTSPQTask)_queue.top();
66-
YBTaskBlock taskBlock = (YBTaskBlock)pqTask.first;
78+
YBTaskBlock taskBlock = pqTask.taskBlock;
6779
_queue.pop();
6880
pthread_mutex_unlock(&_lock);
6981

YBTaskScheduler/YBTaskScheduler+Internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ NS_ASSUME_NONNULL_BEGIN
1414

1515
- (void)executeTasks;
1616

17+
- (BOOL)empty;
18+
1719
@end
1820

1921
NS_ASSUME_NONNULL_END

YBTaskScheduler/YBTaskScheduler.h

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,34 @@ NS_ASSUME_NONNULL_BEGIN
1313

1414
@interface YBTaskScheduler : NSObject
1515

16+
/**
17+
初始化方法
18+
19+
@param strategy 调度策略
20+
@return instancetype
21+
*/
1622
- (instancetype)initWithStrategy:(YBTaskSchedulerStrategy)strategy;
17-
+ (instancetype)schedulerWithStrategy:(YBTaskSchedulerStrategy)strategy;
1823

19-
/* 每次循环周期执行的任务数量 */
20-
@property (nonatomic, assign) NSUInteger numberOfExecuteEachTime;
24+
/**
25+
快速构造方法
26+
27+
@param strategy 调度策略
28+
@return instancetype
29+
*/
30+
+ (instancetype)schedulerWithStrategy:(YBTaskSchedulerStrategy)strategy;
2131

22-
/* 执行任务的线程队列 */
32+
/* 执行任务的线程队列(若不指定,任务会并行执行) */
2333
@property (nullable, nonatomic, strong) dispatch_queue_t taskQueue;
2434

25-
/* 最大持有任务数量 */
35+
/* 最大持有任务数量(调度策略为 YBTaskSchedulerStrategyPriority 时无效) */
2636
@property (nonatomic, assign) NSUInteger maxNumberOfTasks;
2737

38+
/* 每次执行的任务数量 */
39+
@property (nonatomic, assign) NSUInteger executeNumber;
40+
41+
/* 执行频率(RunLoop 循环 executeFrequency 次执行一次任务) */
42+
@property (nonatomic, assign) NSUInteger executeFrequency;
43+
2844
/**
2945
添加任务
3046
@@ -33,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
3349
- (void)addTask:(YBTaskBlock)task;
3450

3551
/**
36-
添加带优先级的任务(仅调度策略为 YBTaskSchedulerStrategyPriority 时有效)
52+
添加带优先级的任务(优先级仅在调度策略为 YBTaskSchedulerStrategyPriority 时有效)
3753
3854
@param task 包裹任务的 block
3955
@param priority 优先级

YBTaskScheduler/YBTaskScheduler.m

Lines changed: 69 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ static dispatch_queue_t defaultConcurrentQueue() {
2727
queueCount = queueCount < 8 ? 8 : queueCount > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : queueCount;
2828
if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
2929
for (NSUInteger i = 0; i < queueCount; i++) {
30-
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT+1, 0);
30+
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0);
3131
queues[i] = dispatch_queue_create("com.yb.taskScheduler", attr);
3232
}
3333
} else {
@@ -43,12 +43,35 @@ static dispatch_queue_t defaultConcurrentQueue() {
4343
}
4444

4545

46+
static CADisplayLink *displayLink;
47+
static pthread_mutex_t displayLinkLock;
48+
49+
static void keepRunLoopActive() {
50+
static dispatch_once_t onceToken;
51+
dispatch_once(&onceToken, ^{
52+
displayLink = [CADisplayLink displayLinkWithTarget:YBTaskScheduler.self selector:@selector(hash)];
53+
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
54+
pthread_mutex_init(&displayLinkLock, NULL);
55+
});
56+
pthread_mutex_lock(&displayLinkLock);
57+
if (displayLink.paused) {
58+
displayLink.paused = NO;
59+
}
60+
pthread_mutex_unlock(&displayLinkLock);
61+
}
62+
63+
4664
static NSHashTable *taskSchedulers;
4765

4866
static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
67+
BOOL keepActive = NO;
4968
for (YBTaskScheduler *scheduler in taskSchedulers.allObjects) {
50-
[scheduler executeTasks];
69+
if (!scheduler.empty) {
70+
keepActive = YES;
71+
[scheduler executeTasks];
72+
}
5173
}
74+
displayLink.paused = !keepActive;
5275
}
5376

5477
static void addRunLoopObserver() {
@@ -62,82 +85,55 @@ static void addRunLoopObserver() {
6285
}
6386

6487

65-
static CADisplayLink *displayLink;
66-
static int32_t displayLinkCounter = 0;
67-
static pthread_mutex_t displayLinkLock;
68-
69-
static void addDisplayLink() {
70-
static dispatch_once_t onceToken;
71-
dispatch_once(&onceToken, ^{
72-
displayLink = [CADisplayLink displayLinkWithTarget:YBTaskScheduler.self selector:@selector(hash)];
73-
pthread_mutex_init(&displayLinkLock, NULL);
74-
});
75-
int32_t counter = OSAtomicIncrement32(&displayLinkCounter);
76-
if (counter >= 1) {
77-
pthread_mutex_lock(&displayLinkLock);
78-
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
79-
pthread_mutex_unlock(&displayLinkLock);
80-
}
81-
}
82-
83-
static void removeDisplayLink() {
84-
int32_t counter = OSAtomicDecrement32(&displayLinkCounter);
85-
if (counter <= 0) {
86-
pthread_mutex_lock(&displayLinkLock);
87-
if (displayLink) {
88-
[displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
89-
}
90-
pthread_mutex_unlock(&displayLinkLock);
91-
}
92-
}
93-
94-
9588
@implementation YBTaskScheduler {
9689
id<YBTaskSchedulerStrategyProtocol> _strategy;
90+
NSUInteger _frequencyCounter;
9791
}
9892

9993
#pragma mark - life cycle
10094

101-
- (void)dealloc {
102-
NSLog(@"释放:%@", self);
103-
removeDisplayLink();
104-
}
105-
106-
- (instancetype)initWithStrategy:(YBTaskSchedulerStrategy)strategy {
95+
- (instancetype)initWithStrategyObject:(id<YBTaskSchedulerStrategyProtocol>)strategyObject {
10796
self = [super init];
10897
if (self) {
109-
addDisplayLink();
11098
addRunLoopObserver();
111-
self.numberOfExecuteEachTime = 1;
99+
self.executeNumber = 1;
112100
self.maxNumberOfTasks = NSUIntegerMax;
113-
switch (strategy) {
114-
case YBTaskSchedulerStrategyLIFO:
115-
_strategy = [YBTSStack new];
116-
break;
117-
case YBTaskSchedulerStrategyFIFO:
118-
_strategy = [YBTSQueue new];
119-
break;
120-
case YBTaskSchedulerStrategyPriority:
121-
_strategy = [YBTSPriorityQueue new];
122-
break;
123-
}
101+
self.executeFrequency = 1;
102+
_strategy = strategyObject;
124103
[taskSchedulers addObject:self];
125104
}
126105
return self;
127106
}
128107

108+
- (instancetype)initWithStrategy:(YBTaskSchedulerStrategy)strategy {
109+
id<YBTaskSchedulerStrategyProtocol> strategyObject;
110+
switch (strategy) {
111+
case YBTaskSchedulerStrategyLIFO:
112+
strategyObject = [YBTSStack new];
113+
break;
114+
case YBTaskSchedulerStrategyFIFO:
115+
strategyObject = [YBTSQueue new];
116+
break;
117+
case YBTaskSchedulerStrategyPriority:
118+
strategyObject = [YBTSPriorityQueue new];
119+
break;
120+
}
121+
return [self initWithStrategyObject:strategyObject];
122+
}
123+
129124
+ (instancetype)schedulerWithStrategy:(YBTaskSchedulerStrategy)strategy {
130125
return [[YBTaskScheduler alloc] initWithStrategy:strategy];
131126
}
132127

133128
#pragma mark - public
134129

135130
- (void)addTask:(YBTaskBlock)task {
136-
if (!task) return;
137-
[_strategy ybts_addTask:task priority:YBTaskPriorityDefault];
131+
[self addTask:task priority:YBTaskPriorityDefault];
138132
}
139133

140134
- (void)addTask:(YBTaskBlock)task priority:(YBTaskPriority)priority {
135+
if (!task) return;
136+
keepRunLoopActive();
141137
[_strategy ybts_addTask:task priority:priority];
142138
}
143139

@@ -147,7 +143,17 @@ - (void)clearTasks {
147143

148144
#pragma mark - internal
149145

146+
- (BOOL)empty {
147+
return _strategy.ybts_empty;
148+
}
149+
150150
- (void)executeTasks {
151+
if (_frequencyCounter != self.executeFrequency) {
152+
++_frequencyCounter;
153+
return;
154+
} else {
155+
_frequencyCounter = 1;
156+
}
151157
if (_strategy.ybts_empty) return;
152158

153159
dispatch_block_t taskBlock = ^{
@@ -161,16 +167,23 @@ - (void)executeTasks {
161167
taskBlock();
162168
};
163169

164-
for (NSUInteger i = 0; i < self.numberOfExecuteEachTime; ++i) {
170+
for (NSUInteger i = 0; i < self.executeNumber; ++i) {
165171
executeBlock();
166172
}
167173
}
168174

169-
#pragma mark - getter & setter
175+
#pragma mark - setter
170176

171177
- (void)setMaxNumberOfTasks:(NSUInteger)maxNumberOfTasks {
172178
_maxNumberOfTasks = maxNumberOfTasks;
173-
_strategy.ybts_maxNumberOfTasks = maxNumberOfTasks;
179+
if ([_strategy respondsToSelector:@selector(setYbts_maxNumberOfTasks:)]) {
180+
_strategy.ybts_maxNumberOfTasks = maxNumberOfTasks;
181+
}
182+
}
183+
184+
- (void)setExecuteFrequency:(NSUInteger)executeFrequency {
185+
_executeFrequency = executeFrequency;
186+
_frequencyCounter = executeFrequency;
174187
}
175188

176189
@end

YBTaskScheduler/YBTaskSchedulerStrategyProtocol.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ NS_ASSUME_NONNULL_BEGIN
2323

2424
- (BOOL)ybts_empty;
2525

26+
@optional
27+
2628
@property (nonatomic, assign) NSUInteger ybts_maxNumberOfTasks;
2729

2830
@end

YBTaskSchedulerDemo.xcodeproj/project.pbxproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
2325627321E04B6A009BEE6C /* YBTSQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = YBTSQueue.mm; sourceTree = "<group>"; };
4747
2325627421E04B6A009BEE6C /* YBTSStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YBTSStack.h; sourceTree = "<group>"; };
4848
2325627521E04B6A009BEE6C /* YBTSStack.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = YBTSStack.mm; sourceTree = "<group>"; };
49+
2325627A21E05B5A009BEE6C /* PrefixHeader.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrefixHeader.pch; sourceTree = "<group>"; };
4950
236645D721DDE77A00AE3AA8 /* YBTaskSchedulerDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YBTaskSchedulerDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
5051
236645DA21DDE77A00AE3AA8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
5152
236645DB21DDE77A00AE3AA8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -72,6 +73,7 @@
7273
231CADA521DF3396003A6FE9 /* YYFPS */,
7374
236645DA21DDE77A00AE3AA8 /* AppDelegate.h */,
7475
236645DB21DDE77A00AE3AA8 /* AppDelegate.m */,
76+
2325627A21E05B5A009BEE6C /* PrefixHeader.pch */,
7577
236645E521DDE77C00AE3AA8 /* LaunchScreen.storyboard */,
7678
236645E821DDE77C00AE3AA8 /* Info.plist */,
7779
236645E921DDE77C00AE3AA8 /* main.m */,
@@ -115,9 +117,9 @@
115117
2325626A21E04B6A009BEE6C /* YBTaskScheduler */ = {
116118
isa = PBXGroup;
117119
children = (
118-
2325626B21E04B6A009BEE6C /* YBTaskScheduler+Internal.h */,
119120
2325626C21E04B6A009BEE6C /* YBTaskScheduler.h */,
120121
2325626D21E04B6A009BEE6C /* YBTaskScheduler.m */,
122+
2325626B21E04B6A009BEE6C /* YBTaskScheduler+Internal.h */,
121123
2325626E21E04B6A009BEE6C /* YBTaskSchedulerStrategyProtocol.h */,
122124
2325626F21E04B6A009BEE6C /* YBTaskSchedulerTypedef.h */,
123125
2325627021E04B6A009BEE6C /* YBTSPriorityQueue.h */,
@@ -373,6 +375,7 @@
373375
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
374376
CODE_SIGN_STYLE = Automatic;
375377
DEVELOPMENT_TEAM = UU8H9EQ986;
378+
GCC_PREFIX_HEADER = "$(SRCROOT)/YBTaskSchedulerDemo/PrefixHeader.pch";
376379
INFOPLIST_FILE = YBTaskSchedulerDemo/Info.plist;
377380
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
378381
LD_RUNPATH_SEARCH_PATHS = (
@@ -391,6 +394,7 @@
391394
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
392395
CODE_SIGN_STYLE = Automatic;
393396
DEVELOPMENT_TEAM = UU8H9EQ986;
397+
GCC_PREFIX_HEADER = "$(SRCROOT)/YBTaskSchedulerDemo/PrefixHeader.pch";
394398
INFOPLIST_FILE = YBTaskSchedulerDemo/Info.plist;
395399
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
396400
LD_RUNPATH_SEARCH_PATHS = (

0 commit comments

Comments
 (0)