354 lines
9.5 KiB
Objective-C
354 lines
9.5 KiB
Objective-C
//
|
|
// QNTransactionManager.m
|
|
// QiniuSDK
|
|
//
|
|
// Created by yangsen on 2020/4/1.
|
|
// Copyright © 2020 Qiniu. All rights reserved.
|
|
//
|
|
|
|
#import "QNDefine.h"
|
|
#import "QNTransactionManager.h"
|
|
|
|
//MARK: -- 事务对象
|
|
typedef NS_ENUM(NSInteger, QNTransactionType){
|
|
QNTransactionTypeNormal, // 普通类型事务,事务体仅会执行一次
|
|
QNTransactionTypeTime, // 定时事务,事务体会定时执行
|
|
};
|
|
|
|
@interface QNTransaction()
|
|
// 事务类型
|
|
@property(nonatomic, assign)QNTransactionType type;
|
|
// 定时任务执行时间间隔
|
|
@property(nonatomic, assign)NSInteger interval;
|
|
// 事务延后时间 单位:秒
|
|
@property(nonatomic, assign)NSInteger after;
|
|
// 事务执行时间 与事务管理者定时器时间相关联
|
|
@property(nonatomic, assign)double createTime;
|
|
// 执行次数
|
|
@property(nonatomic, assign)long executedCount;
|
|
// 下次执行时的时间戳
|
|
@property(nonatomic, assign)double nextExecutionTime;
|
|
|
|
// 事务名称
|
|
@property(nonatomic, copy)NSString *name;
|
|
// 事务执行体
|
|
@property(nonatomic, copy)void(^action)(void);
|
|
// 下一个需要处理的事务
|
|
@property(nonatomic, strong, nullable)QNTransaction *nextTransaction;
|
|
|
|
@end
|
|
@implementation QNTransaction
|
|
|
|
+ (instancetype)transaction:(NSString *)name
|
|
after:(NSInteger)after
|
|
action:(void (^)(void))action{
|
|
QNTransaction *transaction = [[QNTransaction alloc] init];
|
|
transaction.type = QNTransactionTypeNormal;
|
|
transaction.after = after;
|
|
transaction.name = name;
|
|
transaction.action = action;
|
|
transaction.executedCount = 0;
|
|
transaction.createTime = [[NSDate date] timeIntervalSince1970];
|
|
transaction.nextExecutionTime = transaction.createTime + after;
|
|
return transaction;
|
|
}
|
|
|
|
+ (instancetype)timeTransaction:(NSString *)name
|
|
after:(NSInteger)after
|
|
interval:(NSInteger)interval
|
|
action:(void (^)(void))action{
|
|
QNTransaction *transaction = [[QNTransaction alloc] init];
|
|
transaction.type = QNTransactionTypeTime;
|
|
transaction.after = after;
|
|
transaction.name = name;
|
|
transaction.interval = interval;
|
|
transaction.action = action;
|
|
transaction.executedCount = 0;
|
|
transaction.createTime = [[NSDate date] timeIntervalSince1970];
|
|
transaction.nextExecutionTime = transaction.createTime + after;
|
|
return transaction;
|
|
}
|
|
|
|
- (BOOL)shouldAction {
|
|
double currentTime = [[NSDate date] timeIntervalSince1970];
|
|
if (self.type == QNTransactionTypeNormal) {
|
|
return self.executedCount < 1 && currentTime >= self.nextExecutionTime;
|
|
} else if (self.type == QNTransactionTypeTime) {
|
|
return currentTime >= self.nextExecutionTime;
|
|
} else {
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
- (BOOL)maybeCompleted {
|
|
if (self.type == QNTransactionTypeNormal) {
|
|
return self.executedCount > 0;
|
|
} else if (self.type == QNTransactionTypeTime) {
|
|
return false;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
- (void)handleAction {
|
|
if (![self shouldAction]) {
|
|
return;
|
|
}
|
|
if (self.action) {
|
|
_isExecuting = YES;
|
|
self.executedCount += 1;
|
|
self.nextExecutionTime = [[NSDate date] timeIntervalSince1970] + self.interval;
|
|
self.action();
|
|
_isExecuting = NO;
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
//MARK: -- 事务链表
|
|
@interface QNTransactionList : NSObject
|
|
|
|
@property(nonatomic, strong)QNTransaction *header;
|
|
|
|
@end
|
|
@implementation QNTransactionList
|
|
|
|
- (BOOL)isEmpty{
|
|
if (self.header == nil) {
|
|
return YES;
|
|
} else {
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
- (NSArray <QNTransaction *> *)transactionsForName:(NSString *)name{
|
|
NSMutableArray *transactions = [NSMutableArray array];
|
|
[self enumerate:^(QNTransaction *transaction, BOOL * _Nonnull stop) {
|
|
if ((name == nil && transaction.name == nil)
|
|
|| (name != nil && transaction.name != nil && [transaction.name isEqualToString:name])) {
|
|
[transactions addObject:transaction];
|
|
}
|
|
}];
|
|
return [transactions copy];
|
|
}
|
|
|
|
- (void)enumerate:(void(^)(QNTransaction *transaction, BOOL * _Nonnull stop))handler {
|
|
if (!handler) {
|
|
return;
|
|
}
|
|
BOOL isStop = NO;
|
|
QNTransaction *transaction = self.header;
|
|
while (transaction && !isStop) {
|
|
handler(transaction, &isStop);
|
|
transaction = transaction.nextTransaction;
|
|
}
|
|
}
|
|
|
|
- (void)add:(QNTransaction *)transaction{
|
|
|
|
@synchronized (self) {
|
|
QNTransaction *transactionP = self.header;
|
|
while (transactionP.nextTransaction) {
|
|
transactionP = transactionP.nextTransaction;
|
|
}
|
|
|
|
if (transactionP) {
|
|
transactionP.nextTransaction = transaction;
|
|
} else {
|
|
self.header = transaction;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)remove:(QNTransaction *)transaction{
|
|
|
|
@synchronized (self) {
|
|
QNTransaction *transactionP = self.header;
|
|
QNTransaction *transactionLast = nil;
|
|
while (transactionP) {
|
|
if (transactionP == transaction) {
|
|
if (transactionLast) {
|
|
transactionLast.nextTransaction = transactionP.nextTransaction;
|
|
} else {
|
|
self.header = transactionP.nextTransaction;
|
|
}
|
|
break;
|
|
}
|
|
transactionLast = transactionP;
|
|
transactionP = transactionP.nextTransaction;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (BOOL)has:(QNTransaction *)transaction{
|
|
@synchronized (self) {
|
|
__block BOOL has = NO;
|
|
[self enumerate:^(QNTransaction *transactionP, BOOL * _Nonnull stop) {
|
|
if (transaction == transactionP) {
|
|
has = YES;
|
|
*stop = YES;
|
|
}
|
|
}];
|
|
return has;
|
|
}
|
|
}
|
|
|
|
- (void)removeAll{
|
|
@synchronized (self) {
|
|
self.header = nil;
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
//MARK: -- 事务管理者
|
|
@interface QNTransactionManager()
|
|
// 事务处理线程
|
|
@property(nonatomic, strong)NSThread *thread;
|
|
// 事务链表
|
|
@property(nonatomic, strong)QNTransactionList *transactionList;
|
|
|
|
// 事务定时器
|
|
@property(nonatomic, strong)NSTimer *timer;
|
|
|
|
@end
|
|
@implementation QNTransactionManager
|
|
|
|
+ (instancetype)shared{
|
|
static QNTransactionManager *manager = nil;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
manager = [[QNTransactionManager alloc] init];
|
|
});
|
|
return manager;
|
|
}
|
|
- (instancetype)init{
|
|
if (self = [super init]) {
|
|
_transactionList = [[QNTransactionList alloc] init];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (NSArray <QNTransaction *> *)transactionsForName:(NSString *)name{
|
|
return [self.transactionList transactionsForName:name];
|
|
}
|
|
|
|
- (BOOL)existTransactionsForName:(NSString *)name{
|
|
NSArray *transactionList = [self transactionsForName:name];
|
|
if (transactionList && transactionList.count > 0) {
|
|
return YES;
|
|
} else {
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
- (void)addTransaction:(QNTransaction *)transaction{
|
|
if (transaction == nil) {
|
|
return;
|
|
}
|
|
[self.transactionList add:transaction];
|
|
[self createThread];
|
|
}
|
|
|
|
- (void)removeTransaction:(QNTransaction *)transaction{
|
|
if (transaction == nil) {
|
|
return;
|
|
}
|
|
[self.transactionList remove:transaction];
|
|
}
|
|
|
|
- (void)performTransaction:(QNTransaction *)transaction{
|
|
if (transaction == nil) {
|
|
return;
|
|
}
|
|
@synchronized (self) {
|
|
if (![self.transactionList has:transaction]) {
|
|
[self.transactionList add:transaction];
|
|
}
|
|
transaction.createTime = [[NSDate date] timeIntervalSince1970] - transaction.interval;
|
|
}
|
|
}
|
|
|
|
/// 销毁资源
|
|
- (void)destroyResource{
|
|
|
|
@synchronized (self) {
|
|
[self invalidateTimer];
|
|
[self.thread cancel];
|
|
self.thread = nil;
|
|
[self.transactionList removeAll];
|
|
}
|
|
}
|
|
|
|
|
|
//MARK: -- handle transaction action
|
|
- (void)handleAllTransaction{
|
|
|
|
[self.transactionList enumerate:^(QNTransaction *transaction, BOOL * _Nonnull stop) {
|
|
[self handleTransaction:transaction];
|
|
if ([transaction maybeCompleted]) {
|
|
[self removeTransaction:transaction];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)handleTransaction:(QNTransaction *)transaction{
|
|
[transaction handleAction];
|
|
}
|
|
|
|
//MARK: -- thread
|
|
- (void)createThread{
|
|
@synchronized (self) {
|
|
if (self.thread == nil) {
|
|
kQNWeakSelf;
|
|
self.thread = [[NSThread alloc] initWithTarget:weak_self
|
|
selector:@selector(threadAction)
|
|
object:nil];
|
|
self.thread.name = @"com.qiniu.transaction";
|
|
[self.thread start];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)threadAction{
|
|
|
|
@autoreleasepool {
|
|
if (self.timer == nil) {
|
|
[self createTimer];
|
|
}
|
|
NSThread *thread = [NSThread currentThread];
|
|
while (thread && !thread.isCancelled) {
|
|
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
|
beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
|
}
|
|
}
|
|
}
|
|
|
|
//MARK: -- timer
|
|
- (void)createTimer{
|
|
kQNWeakSelf;
|
|
NSTimer *timer = [NSTimer timerWithTimeInterval:1
|
|
target:weak_self
|
|
selector:@selector(timerAction)
|
|
userInfo:nil
|
|
repeats:YES];
|
|
[[NSRunLoop currentRunLoop] addTimer:timer
|
|
forMode:NSDefaultRunLoopMode];
|
|
|
|
[self timerAction];
|
|
_timer = timer;
|
|
}
|
|
|
|
- (void)invalidateTimer{
|
|
[self.timer invalidate];
|
|
self.timer = nil;
|
|
}
|
|
|
|
- (void)timerAction{
|
|
[self handleAllTransaction];
|
|
}
|
|
|
|
@end
|