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=%@
reasion=%@
userInfo=", 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 }