NSRunLoop
Runloop作用: 主线程Runloop默认开启,子线程的Runloop需要手动开启。
常驻线程,Crash的程序回光返照, 在tracking mode下不加载图片等等。
与Runloop有关的5种类型:
CFRunLoopRef:
CFRunLoopModeRef: 运行模式
CFRunLoopTimerRef:定时器时间或者生命周期
CFRunLoopSourceRef: 输入源或者时间源
CFRunLoopObservalRef: 观察者。
1. CFRunLoopModeRef
kCFRunLoopDefaultMode, 默认的mode,通常主线程在这个mode下运行。
kCFRunLoopCommonModes,占位mode,通常标记defaultMode和CommonMode用。
UITrackingRunLoopMode, 追踪mode, 保证scrollView滑动顺畅,不受其它mode影响。
UIInitializationRunLoopMode, 启动程序后的过度mode,启动完成后不再使用。
GSEventReceiveRunLoopMode, Graphic事件相关的mode。
程序崩溃时的回光返照
#import <UIKit/UIKit.h> #import <signal.h> @interface FFExceptionCaptureHandle : NSObject + (instancetype)share; - (void)exercute:(NSString *)str; @end #import "FFExceptionCaptureHandle.h" /** 系统未捕获的异常,如下标越界,数组中插入nil, 重复释放等等 @param ception 异常信息 */ void handleException(NSException *ception) { NSLog(@"111"); NSString *name = ception.name; NSString *reasion = ception.reason; NSDictionary *userInfo = ception.userInfo; NSString *userInfoStr = [NSString stringWithFormat:@"name=%@\nreasion=%@\nuserInfo=", name, reasion]; if (userInfo) { for (NSString *key in userInfo.allKeys) { NSString *temp = [NSString stringWithFormat:@"%@=%@", key, userInfo[key]]; userInfoStr = [userInfoStr stringByAppendingString:temp]; } } [[FFExceptionCaptureHandle share] exercute:userInfoStr]; } /** 系统直接发出的异常signal @param signal 信号类型 */ void signalHandle(int signal) { NSString * userinfoStr = [NSString stringWithFormat:@"系统发送异常信号 = %d", signal]; [[FFExceptionCaptureHandle share] exercute:userinfoStr]; } //void @implementation FFExceptionCaptureHandle + (instancetype)share{ static FFExceptionCaptureHandle *handle = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ handle = [super allocWithZone:nil]; [handle FFSetExceptionCapture]; }); return handle; } - (void)FFSetExceptionCapture { NSSetUncaughtExceptionHandler(&handleException); signal(SIGABRT, signalHandle); signal(SIGILL, signalHandle); signal(SIGSEGV, signalHandle); signal(SIGFPE, signalHandle); signal(SIGBUS, signalHandle); signal(SIGPIPE, signalHandle); } /** 接受到异常时候的处理 @param str 异常信息 */ - (void)exercute:(NSString *)str { CFRunLoopRef runloop = CFRunLoopGetCurrent(); NSArray *allModels = CFBridgingRelease(CFRunLoopCopyAllModes(runloop)); UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"程序崩溃了" message:str delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil]; [alertView show]; while (1) { for (NSString *model in allModels) { CFRunLoopRunInMode((CFStringRef)model, 0.001, false); } } } + (id)allocWithZone:(struct _NSZone *)zone { return [self share]; } - (id)mutableCopyWithZone:(NSZone *)zone{ return [FFExceptionCaptureHandle share]; } - (id)copyWithZone:(NSZone *)zone { return [FFExceptionCaptureHandle share]; } @end
1 - (void)addThrea 2 { 3 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(createRunLoop) object:nil 4 ]; 5 /// 线程名称 6 thread.name = @"xxx"; 7 /// 开始线程 8 [thread start]; 9 /// 防止thread被立即销毁。 10 self.thread = thread; 11 } 12 13 - (void)createRunLoop 14 { 15 /// 主线程中的RunLoop会自动生成,子线程中的RunLoop在调用currentRunLoop时生成. 16 /// 防止runloop被销毁。 17 self.runloop = [NSRunLoop currentRunLoop]; 18 /// runloop的context 19 CFRunLoopObserverContext context = {0, (__bridge void *)self, NULL, NULL, NULL}; 20 /// runloop的observer 21 CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context); 22 if (observer) { 23 CFRunLoopAddObserver([_runloop getCFRunLoop], observer, kCFRunLoopDefaultMode); 24 } 25 /// 添加事件, 在两秒执行完后,runloop退出 26 [self performSelector:@selector(handleEvent:) withObject:@"测试" afterDelay:2]; 27 /// 添加端口事件保证保证runloop长驻 28 [_runloop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; 29 /// 30 [self addSourceEvent]; 31 /// 退出runloop 32 [_runloop run]; 33 34 } 35 36 /// runloop观察者回调 37 void myRunLoopObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) 38 { 39 if (activity & kCFRunLoopEntry) { 40 NSLog(@"调用runloop"); 41 }else if (activity & kCFRunLoopBeforeTimers) { 42 NSLog(@"即将处理计时器事件"); 43 }else if (activity & kCFRunLoopBeforeSources) { 44 NSLog(@"即将处理source事件 "); 45 }else if (activity & kCFRunLoopBeforeWaiting) { 46 NSLog(@"即将休眠"); 47 }else if (activity & kCFRunLoopAfterWaiting) { 48 NSLog(@"从休眠中唤醒"); 49 }else if (activity & kCFRunLoopExit) { 50 NSLog(@"退出runloop"); 51 } 52 } 53 54 /// 事件 55 - (void)handleEvent:(NSString *)str 56 { 57 NSLog(@"%@", str); 58 } 59 60 /// 添加source 61 - (void)addSourceEvent 62 { 63 CFRunLoopSourceContext context = {0, (__bridge void *)self, NULL, NULL, NULL, NULL, NULL, &mySchedule, &myCancel, &myPerform}; 64 CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); 65 CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); 66 /// 将source将标记为待处理 67 CFRunLoopSourceSignal(source); 68 /// 唤醒runloop 69 CFRunLoopWakeUp(CFRunLoopGetCurrent()); 70 71 } 72 73 /// 添加输入源时的回调 74 void mySchedule(void *info, CFRunLoopRef rl, CFRunLoopMode mode) 75 { 76 NSLog(@"输入源被添加"); 77 } 78 79 /// 移除输入源时的回调 80 void myCancel(void *info, CFRunLoopRef rl, CFRunLoopMode mode) 81 { 82 NSLog(@"输入源被移除"); 83 } 84 85 /// 执行输入源时的回调 86 void myPerform(void *info) 87 { 88 NSLog(@"输入源正在被执行"); 89 }