iOS的CoreFoundation框架是開源的
NSRunloop只是對CFRunLoop的封裝奋刽,CFRunLoop在CoreFoundation中政供。
示例demo
CFRunLoop
struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* locked for accessing mode list */
__CFPort _wakeUpPort; // used for CFRunLoopWakeUp
Boolean _unused;
volatile _per_run_data *_perRunData; // reset for runs of the run loop
pthread_t _pthread;
uint32_t _winthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFTypeRef _counterpart;
};
CFRunLoopMode
struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* must have the run loop locked before locking this */
CFStringRef _name;
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
CFMutableDictionaryRef _portToV1SourceMap;
__CFPortSet _portSet;
CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
dispatch_source_t _timerSource;
dispatch_queue_t _queue;
Boolean _timerFired; // set to true by the source when a timer has fired
Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
mach_port_t _timerPort;
Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
DWORD _msgQMask;
void (*_msgPump)(void);
#endif
uint64_t _timerSoftDeadline; /* TSR */
uint64_t _timerHardDeadline; /* TSR */
};
CFRunLoopSource
struct __CFRunLoopSource {
CFRuntimeBase _base;
uint32_t _bits;
pthread_mutex_t _lock;
CFIndex _order; /* immutable */
CFMutableBagRef _runLoops;
union {
CFRunLoopSourceContext version0; /* immutable, except invalidation */
CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
} _context;
};
CFRunLoopObserver
struct __CFRunLoopObserver {
CFRuntimeBase _base;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFIndex _rlCount;
CFOptionFlags _activities; /* immutable */
CFIndex _order; /* immutable */
CFRunLoopObserverCallBack _callout; /* immutable */
CFRunLoopObserverContext _context; /* immutable, except invalidation */
};
CFRunLoopTimer
struct __CFRunLoopTimer {
CFRuntimeBase _base;
uint16_t _bits;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFMutableSetRef _rlModes;
CFAbsoluteTime _nextFireDate;
CFTimeInterval _interval; /* immutable */
CFTimeInterval _tolerance; /* mutable */
uint64_t _fireTSR; /* TSR units */
CFIndex _order; /* immutable */
CFRunLoopTimerCallBack _callout; /* immutable */
CFRunLoopTimerContext _context; /* immutable, except invalidation */
};
RunLoop內(nèi)部執(zhí)行過程
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
__CFRunLoopLock(rl);
/// 首先根據(jù)modeName找到對應mode
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
/// 通知 Observers: RunLoop 即將進入 loop愧旦。
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
/// 內(nèi)部函數(shù)缸匪,進入loop
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
/// 通知 Observers: RunLoop 即將退出斋泄。
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
return result;
}
/// 核心函數(shù)
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
int32_t retVal = 0;
do { // itmes do
/// 通知 Observers: 即將處理timer事件
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
/// 通知 Observers: 即將處理Source事件
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources)
/// 處理Blocks
__CFRunLoopDoBlocks(rl, rlm);
/// 處理sources0
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
/// 處理sources0返回為YES
if (sourceHandledThisLoop) {
/// 處理Blocks
__CFRunLoopDoBlocks(rl, rlm);
}
/// 判斷有無端口消息(Source1)
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
/// 處理消息
goto handle_msg;
}
/// 通知 Observers: 即將進入休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);
/// 等待被喚醒
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
// user callouts now OK again
__CFRunLoopUnsetSleeping(rl);
/// 通知 Observers: 被喚醒握侧,結(jié)束休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
handle_msg:
if (被Timer喚醒) {
/// 處理Timers
__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())亲雪;
} else if (被GCD喚醒) {
/// 處理gcd
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
} else if (被Source1喚醒) {
/// 被Source1喚醒里初,處理Source1
__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)
}
/// 處理block
__CFRunLoopDoBlocks(rl, rlm);
if (sourceHandledThisLoop && stopAfterHandle) {
retVal = kCFRunLoopRunHandledSource;
} else if (timeout_context->termTSR < mach_absolute_time()) {
retVal = kCFRunLoopRunTimedOut;
} else if (__CFRunLoopIsStopped(rl)) {
__CFRunLoopUnsetStopped(rl);
retVal = kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
rlm->_stopped = false;
retVal = kCFRunLoopRunStopped;
} else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
retVal = kCFRunLoopRunFinished;
}
} while (0 == retVal);
return retVal;
}
// main dispatch queue
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
// __CFRunLoopDoObservers
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
// __CFRunLoopDoBlocks
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__
// __CFRunLoopDoSources0
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
// __CFRunLoopDoSource1
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
// __CFRunLoopDoTimers
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
分析示例
#import "ViewController.h"
//#import "LGThread.h"
#import <objc/message.h>
@interface ViewController ()<NSPortDelegate>
@property (nonatomic, strong) NSPort* subThreadPort;
@property (nonatomic, strong) NSPort* mainThreadPort;
//@property (nonatomic, assign) BOOL isStopping;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// [self testThredRunLoop];
// [self cfTimerDemo];
// [self cfObseverDemo];
// [self source0Demo];
[self setupPort];
}
//- (void)testThredRunLoop {
// // runloop 和 線程
// // 主運行循環(huán)
// CFRunLoopRef mainRunloop = CFRunLoopGetMain();
// // 當前運行循環(huán)
// CFRunLoopRef currentRunloop = CFRunLoopGetCurrent();
//
// // 子線程runloop 默認不啟動
//
// self.isStopping = NO;
// LGThread *thread = [[LGThread alloc] initWithBlock:^{
//
// // thread.name = nil 因為這個變量只是捕捉
// // LGThread *thread = nil
// // thread = 初始化 捕捉一個nil進來
// NSLog(@"%@---%@",[NSThread currentThread],[[NSThread currentThread] name]);
// [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
// NSLog(@"hello word"); // 退出線程--結(jié)果runloop也停止了
// if (self.isStopping) {
// [NSThread exit];
// }
// }];
// [[NSRunLoop currentRunLoop] run];
// }];
//
// thread.name = @"lgcode.com";
// [thread start];
//}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// self.isStopping = YES;
NSMutableArray* components = [NSMutableArray array];
NSData* data = [@"hello" dataUsingEncoding:NSUTF8StringEncoding];
[components addObject:data];
[self.subThreadPort sendBeforeDate:[NSDate date] components:components from:self.mainThreadPort reserved:0];
}
#pragma mark - mode演練
- (void)timerDemo{
// CFRunLoopMode 研究
CFRunLoopRef lp = CFRunLoopGetCurrent();
CFRunLoopMode mode = CFRunLoopCopyCurrentMode(lp);
NSLog(@"mode == %@",mode);
CFArrayRef modeArray= CFRunLoopCopyAllModes(lp);
NSLog(@"modeArray == %@",modeArray);
NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"fire in home -- %@",[[NSRunLoop currentRunLoop] currentMode]);
}];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
#pragma mark - timer
- (void)cfTimerDemo{
CFRunLoopTimerContext context = {
0,
((__bridge void *)self),
NULL,
NULL,
NULL
};
CFRunLoopRef rlp = CFRunLoopGetCurrent();
/**
參數(shù)一:用于分配對象的內(nèi)存
參數(shù)二:在什么是觸發(fā) (距離現(xiàn)在)
參數(shù)三:每隔多少時間觸發(fā)一次
參數(shù)四:未來參數(shù)
參數(shù)五:CFRunLoopObserver的優(yōu)先級 當在Runloop同一運行階段中有多個CFRunLoopObserver 正常情況下使用0
參數(shù)六:回調(diào),比如觸發(fā)事件,我就會來到這里
參數(shù)七:上下文記錄信息
*/
CFRunLoopTimerRef timerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, 0, 1, 0, 0, lgRunLoopTimerCallBack, &context);
CFRunLoopAddTimer(rlp, timerRef, kCFRunLoopDefaultMode);
}
void lgRunLoopTimerCallBack(CFRunLoopTimerRef timer, void *info){
NSLog(@"%@---%@",timer,info);
}
#pragma mark - observe
- (void)cfObseverDemo{
CFRunLoopObserverContext context = {
0,
((__bridge void *)self),
NULL,
NULL,
NULL
};
CFRunLoopRef rlp = CFRunLoopGetCurrent();
/**
參數(shù)一:用于分配對象的內(nèi)存
參數(shù)二:你關注的事件
kCFRunLoopEntry=(1<<0),
kCFRunLoopBeforeTimers=(1<<1),
kCFRunLoopBeforeSources=(1<<2),
kCFRunLoopBeforeWaiting=(1<<5),
kCFRunLoopAfterWaiting=(1<<6),
kCFRunLoopExit=(1<<7),
kCFRunLoopAllActivities=0x0FFFFFFFU
參數(shù)三:CFRunLoopObserver是否循環(huán)調(diào)用
參數(shù)四:CFRunLoopObserver的優(yōu)先級 當在Runloop同一運行階段中有多個CFRunLoopObserver 正常情況下使用0
參數(shù)五:回調(diào),比如觸發(fā)事件,我就會來到這里
參數(shù)六:上下文記錄信息
*/
CFRunLoopObserverRef observerRef = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, lgRunLoopObserverCallBack, &context);
CFRunLoopAddObserver(rlp, observerRef, kCFRunLoopDefaultMode);
}
void lgRunLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
NSLog(@"%lu-%@",activity,info);
}
#pragma mark - source0:演練
// 就是喜歡玩一下: 我們下面來自定義一個source
- (void)source0Demo{
CFRunLoopSourceContext context = {
0,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
schedule,
cancel,
perform,
};
/**
參數(shù)一:傳遞NULL或kCFAllocatorDefault以使用當前默認分配器惨好。
參數(shù)二:優(yōu)先級索引煌茴,指示處理運行循環(huán)源的順序。這里我傳0為了的就是自主回調(diào)
參數(shù)三:為運行循環(huán)源保存上下文信息的結(jié)構
*/
CFRunLoopSourceRef source0 = CFRunLoopSourceCreate(CFAllocatorGetDefault(), 0, &context);
CFRunLoopRef rlp = CFRunLoopGetCurrent();
// source --> runloop 指定了mode 那么此時我們source就進入待緒狀態(tài)
CFRunLoopAddSource(rlp, source0, kCFRunLoopDefaultMode);
// 一個執(zhí)行信號
CFRunLoopSourceSignal(source0);
// 喚醒 run loop 防止沉睡狀態(tài)
CFRunLoopWakeUp(rlp);
// 取消 移除
CFRunLoopRemoveSource(rlp, source0, kCFRunLoopDefaultMode);
CFRelease(rlp);
}
void schedule(void *info, CFRunLoopRef rl, CFRunLoopMode mode){
NSLog(@"準備代發(fā)");
}
void perform(void *info){
NSLog(@"執(zhí)行吧,騷年");
}
void cancel(void *info, CFRunLoopRef rl, CFRunLoopMode mode){
NSLog(@"取消了,終止了!!!!");
}
#pragma mark - source1: port演示
- (void)setupPort{
self.mainThreadPort = [NSPort port];
self.mainThreadPort.delegate = self;
// port - source1 -- runloop
[[NSRunLoop currentRunLoop] addPort:self.mainThreadPort forMode:NSDefaultRunLoopMode];
[self task];
}
- (void) task {
NSThread *thread = [[NSThread alloc] initWithBlock:^{
self.subThreadPort = [NSPort port];
self.subThreadPort.delegate = self;
[[NSRunLoop currentRunLoop] addPort:self.subThreadPort forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
}];
[thread start];
// 主線 -- 子線程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"%@", [NSThread currentThread]); // 3
NSString *str;
dispatch_async(dispatch_get_main_queue(), ^{
// 1
NSLog(@"%@", [NSThread currentThread]);
});
});
}
// 線程之間通訊
// 主線程 -- data
// 子線程 -- data1
// 更加低層 -- 內(nèi)核
// mach
- (void)handlePortMessage:(id)message {
NSLog(@"%@", [NSThread currentThread]); // 3 1
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([message class], &count);
for (int i = 0; i<count; i++) {
NSString *name = [NSString stringWithUTF8String:ivar_getName(ivars[i])];
// NSLog(@"%@",name);
}
sleep(1);
if (![[NSThread currentThread] isMainThread]) {
NSMutableArray* components = [NSMutableArray array];
NSData* data = [@"woard" dataUsingEncoding:NSUTF8StringEncoding];
[components addObject:data];
[self.mainThreadPort sendBeforeDate:[NSDate date] components:components from:self.subThreadPort reserved:0];
}
}
@end