zoukankan      html  css  js  c++  java
  • 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=%@
    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 }

     参考: https://juejin.im/post/59a04e125188252445326e89

  • 相关阅读:
    2016第17周四
    2016第17周三
    2016第17周二
    OSGI框架学习
    2016年第16周日
    2016第16周六
    如何培养技术洞见力
    2016第15周四
    深入浅出ClassLoader
    Linux智能小开关rfkill
  • 原文地址:https://www.cnblogs.com/jisa/p/7486528.html
Copyright © 2011-2022 走看看