= quit); } - NSRunLoop是iOS的消息处理模式, - RunLoop是iOS里线程的一部分,任何线程,包括主线程都包含了一个Run Loop对象。 - NSRunLoop的作用在于有事情做的时候使的当前NSRunLoop的线程工作,没有事情做让当前NSRunLoop的线程休眠。 // 获得当前线程的RunLoop对象 NSRunLoop currentRunLoop]; // 获得主线程的RunLoop对象 [NSRunLoop mainRunLoop]; 一套是Core CFRunLoopObserverRef: 观察者,能够监听RunLoop的状态改 NSRunLoop和CFRunLoopRef都代表着RunLoop对象.NSRunLoop是基于CFRunLoopRef 其中input source分发异步事件给相应的处理程序并且调用runUntilDate:方法(这个方法会在该线程关联的NSRunLoop 对象上被调用)来退出其Run Loop。
众所周知:一个AutoreleasePool对应一个RunLoop,一个RunLoop对应一个线程。但一个RunLoop可以包含多个AutoreleasePool。
must add the timer to a run loop manually by calling the addTimer:forMode: method of the corresponding NSRunLoop must add the timer to a run loop manually by calling the addTimer:forMode: method of the corresponding NSRunLoop .使用timerWithTimerInterval 类方法创建计时器对象没有调度运行循环(RunLoop) 在创建它,必须手动添加计时器运行循环,通过调用adddTimer:forMode:方法相应的NSRunLoop 对象 3.使用initWithFireDate 在创建它,必须手动添加计时器运行循环,通过使用addTimer:forMode:方法相应的NSRunLoop对象 1. - (void)execute { currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run];
, ^{ }); 事件响应、手势识别、界面刷新 网络请求 AutoreleasePool RunLoop 对象 iOS 中有 2 套 API 来访问和使用RunLoop: ① Foundation:NSRunLoop (是CFRunLoopRef的封装,提供了面向对象的 API) ② Core Foundation:CFRunLoopRef NSRunLoop和CFRunLoopRef都代表着RunLoop对象 NSRunLoop不开源,而CFRunLoopRef是开源的:Core Foundation 源码 获取RunLoop对象的方式: // Foundation [NSRunLoop mainRunLoop]; // 获取主线程的 RunLoop 对象 [NSRunLoop currentRunLoop]; // 获取当前线程的 RunLoop 对象 //
timer默认mode, NSRunLoopCommonModes(滑动时主线程会从NSDefaultRunLoopMode切换为UITrackingRunLoopMode,导致timer停止运行) [[NSRunLoop userInfo:userInfo repeats:repeats]; [[NSRunLoop currentRunLoop] addTimer:timerTarget.timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop userInfo:userInfo repeats:repeats]; [[NSRunLoop currentRunLoop] addTimer:timerTarget.timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 2.在子线程中(NSThread开辟新的子线程),使用计时器时 ,需要[[NSRunLoop currentRunLoop] run],(如果NSTimer当前所处的线程正在进行大数据处理(假设为一个大循环),(类似操作列表的滑动过程)使用NSDefaultRunLoopMode timerWithTimeInterval:2.0 target:self selector:@selector(timer_callback) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run]; } }
RunLoop销毁时机:RunLoop会在线程结束时销毁; 主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop; 主线程的RunLoop对象是在UIApplicationMain中通过[NSRunLoop } // HTThread dealloc 开启子线程的 RunLoop 的过程 获取 RunLoop 对象 可以通过以下方式来获取RunLoop对象: // Foundation [NSRunLoop mainRunLoop]; // 获取主线程的 RunLoop 对象 [NSRunLoop currentRunLoop]; // 获取当前线程的 RunLoop 对象 // currentRunLoop] run]; [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate weakSelf.isStoped) { // ③ 启动该 RunLoop /* [[NSRunLoop currentRunLoop
currentRunLoop] addTimer:time forMode:NSDefaultRunLoopMode]; // [[NSRunLoop currentRunLoop] addTimer:time forMode:UITrackingRunLoopMode]; //#else // [[NSRunLoop currentRunLoop] addTimer :time forMode:UITrackingRunLoopMode]; //#else // [[NSRunLoop currentRunLoop] addTimer:time forMode isFinished) { // [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow :0.0001]]; // } // // [[NSRunLoop currentRunLoop] run]; // [time fire]; /
解决方案 定时器的运行需要结合一个 NSRunLoop,同时 NSRunLoop 对该定时器会有一个强引用,这也是为什么我们不对 NSRunLoop 中的定时器进行强引的原因。 由于 NSRunLoop 对定时器有着牵引,那么问题就来了,那么定时器怎样才能被释放掉呢(先不考虑使用removeFromRunLoop:),此时 - invalidate 函数的作用就来了,我们来看看官方就此函数的介绍 据官方介绍可知,- invalidate 做了两件事,首先是把本身(定时器)从 NSRunLoop 中移除,然后就是释放对 target 对象的强引用。从而解决定时器带来的内存泄漏问题。 虽然孤岛问题已经避免了,但还是存在问题,因为 myClock 对象被 UIViewController 以及 timer 引用(timer 直接被 NSRunLoop 强引用着),当 UIViewController 如果对 timer 对象发送一个 invalidate 消息,这样 NSRunLoop 即不会对 timer 进行强引,同时 timer 也会释放对 myClock 对象的强引,这样不就解决了吗?
object { @autoreleasepool { [[NSThread currentThread] setName:@"AFNetworking"]; NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode 开启新的线程时,需要维护自动释放池栈 @autoreleasepool { [[NSThread currentThread] setName:@"AFNetworking"]; NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode
NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerThree) userInfo:nil repeats:YES]; [[NSRunLoop :2] interval:1 repeats:YES block:^(NSTimer * _Nonnull timer) { NSLog(@"timer 6"); }]; // iOS 10 [[NSRunLoop ]; // 解决方案二: [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop ] addTimer:timer forMode:UITrackingRunLoopMode]; 子线程的RunLoop没有创建 // 不获取就不会主动创建 NSRunLoop *runLoop = [ NSRunLoop currentRunLoop]; // 保持线程常驻 [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode
三、认识NSRunLoop NSRunLoop是Cocoa框架中的类,与之对应,在Core Fundation中是CFRunLoopRef类。 我们这里只来讨论NSRunLoop的属性和方法: + (NSRunLoop *)currentRunLoop; 获取当前线程的RunLoop:有则获取,无则创建 + (NSRunLoop *)mainRunLoop }); } -(void)time{ NSLog(@"run"); } 你会发现,程序运行后并没有打印任何信息,方法并没有被调用,我们必须在线程中手动的执行如下代码: [[NSRunLoop
scheduledTimerWithTimeInterval:timerInterval target:self selector:@selector(handleUpload) userInfo:nil repeats:YES]; [[NSRunLoop scheduledTimerWithTimeInterval:timerInterval target:self selector:@selector(handleUpload) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.uploadTimer forMode:NSRunLoopCommonModes]; [[NSRunLoop currentRunLoop
二、RunLoop的数据结构 NSRunLoop(Foundation)是CFRunLoop(CoreFoundation)的封装,提供了面向对象的API RunLoop 相关的主要涉及五个类: CFRunLoop 就要用到NSRunLoopCommonModes了 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; Timer 1、为当前线程开启一个RunLoop(第一次调用 NSRunLoop currentRunLoop方法时实际是会先去创建一个RunLoop) 1、向当前RunLoop中添加一个Port/Source等维持 RunLoop的事件循环(如果RunLoop的mode中一个item都没有,RunLoop会退出) 2、启动该RunLoop @autoreleasepool { NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [[NSRunLoop currentRunLoop] addPort:[NSMachPort port]
获取 RunLoop 对象 为了获取当前线程的 RunLoop ,你可以使用下列方法之一: 使用 NSRunLoop 的 CurrentRunLoop 类方法来获取一个 NSRunLoop 对象。 当需要时,你可以从 NSRunLoop 对象获取一个 CFRunLoopRef 不透明类型指针。 因为两个对象引用相同 NSRunLoop ,如果需要你可以混合调用 NSRunLoop 对象和 CFRunLoopRef 不透明类型。 NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; // Create a run loop observer and attach it to 该子线程主函数入口设计如下: - (void)main { @autoreleasepool { NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop
* runLoop = [NSRunLoop currentRunLoop]; // Add the exitNow BOOL to the thread dictionary. [thread start]; self.thread = thread; } - (void)threadFun { NSLog(@"hello world"); NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode 比如这样:[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];就是把timer放到commonItem里。 如果要在线程中开启runloop,这样写是不对的: [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate
Runloop 该函数返回一个int类型的值 b 这个默认启动的Runloop是跟主线程相关联的 1.3 RunLoop对象 在iOS开发中有两套api来访问Runloop foundation框架【NSRunloop 】 core foundation框架【CFRunloopRef】 NSRunLoop和CFRunLoopRef都代表着RunLoop对象,它们是等价的,可以互相转换 NSRunLoop是基于CFRunLoopRef NSRunLoop * runloop1 = [NSRunLoop currentRunLoop]; //02 CFRunLoopRef CFRunLoopRef runloop2 = CFRunLoopGetCurrent(); /*2.拿到当前应用程序的主Runloop(主线程对应的Runloop)*/ //01 NSRunloop NSRunLoop ]); } - (void)run { NSLog(@"---run---%@",[NSRunLoop currentRunLoop].currentMode); } - (IBAction
Mode启动,如果当前Mode中没有任Source、Timer、Observer,那么就直接退出RunLoop RunLoop里面有两套api用来访问和使用RunLoop 1、Foundation--NSRunLoop 2、Core Foundation --- CFRunloopRef 二者异同点: NSRunLoop和CFRunloopRef都代表RunLoop对象,NSRunLoop是对CFRunloopRef Foundation */ // 获取当前线程 NSRunLoop *roop = [NSRunLoop currentRunLoop]; // 获取主线程 [NSRunLoop Paste_Image.png // 获取当前Runloop的模式 NSString *runloopMode = [NSRunLoop currentRunLoop].currentMode currentRunLoop] addPort:[NSMachPort port] forMode:NSRunLoopCommonModes]; [[NSRunLoop currentRunLoop
timerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES]; [[NSRunLoop - (void)timerUpdate { NSLog(@"当前线程:%@",[NSThread currentThread]); NSLog(@"启动RunLoop后--%@",[NSRunLoop currentRunLoop].currentMode); // NSLog(@"currentRunLoop:%@",[NSRunLoop currentRunLoop]); dispatch_async *runLoop = [NSRunLoop currentRunLoop]; NSLog(@"启动RunLoop前--%@",runLoop.currentMode); NSLog(@"currentRunLoop:%@",[NSRunLoop currentRunLoop]); // 第一种写法,改正前 // NSTimer *timer
runloop可以理解为cocoa下的一种消息循环机制,用来处理各种消息事件,我们在开发 的时候并不需要手动去创建一个runloop,因为框架为我们创建了一个默认的runloop,通过[NSRunloop NSDefaultRunLoopMode 的消息(因为RunLoop Mode不一样),要想在scrollView滚动的同时也接受其它runloop的消息,我们需要改变两者之间的runloopmode. 1 [[NSRunLoop userInfo:nil repeats:YES]; [[NSRunLoop