GCDTimer
@interface GCDTimer: NSObject
+ (GCDTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval
repeats:(BOOL)repeats
queue:(dispatch_queue_t)queue
block:(void (^)(void))block;
- (void)invalidate;
@end
#import "GCDTimer.h"
@interface GCDTimer ()
@property (strong, nonatomic) dispatch_source_t timer;
@end
@implementation GCDTimer
+ (GCDTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval
repeats:(BOOL)repeats
queue:(dispatch_queue_t)queue
block:(void (^)(void))block {
GCDTimer *timer = [[GCDTimer alloc] initWithInterval:interval
repeats:repeats
queue:queue
block:block];
return timer;
}
- (instancetype)initWithInterval:(NSTimeInterval)interval
repeats:(BOOL)repeats
queue:(dispatch_queue_t)queue
block:(void (^)(void))block {
self = [super init];
if (self) {
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, interval * NSEC_PER_SEC), interval * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(self.timer, ^{
if (!repeats) {
dispatch_source_cancel(self.timer);
}
block();
});
dispatch_resume(self.timer);
}
return self;
}
- (void)dealloc {
[self invalidate];
}
- (void)invalidate {
if (self.timer) {
dispatch_source_cancel(self.timer);
}
}
@end
使用GCD 的 source timer 来完成 timer 做的事情.
MQTTCFSocketTransport.m
- (void)setQueue:(dispatch_queue_t)queue {
_queue = queue;
// We're going to use dispatch_queue_set_specific() to "mark" our queue.
// The dispatch_queue_set_specific() and dispatch_get_specific() functions take a "void *key" parameter.
// Later we can use dispatch_get_specific() to determine if we're executing on our queue.
// From the documentation:
//
// > Keys are only compared as pointers and are never dereferenced.
// > Thus, you can use a pointer to a static variable for a specific subsystem or
// > any other value that allows you to identify the value uniquely.
//
// So we're just going to use the memory address of an ivar.
dispatch_queue_set_specific(_queue, &QueueIdentityKey, (__bridge void *)_queue, NULL);
}
- (void)close {
// https://github.com/novastone-media/MQTT-Client-Framework/issues/325
// We need to make sure that we are closing streams on their queue
// Otherwise, we end up with race condition where delegate is deallocated
// but still used by run loop event
if (self.queue != dispatch_get_specific(&QueueIdentityKey)) {
dispatch_sync(self.queue, ^{
[self internalClose];
});
} else {
[self internalClose];
}
}
dispatch_set_specific
来确认线程, 避免 race condition, 过度释放
网友评论