iOS-RunLoop

2015-12-11  本文已影响216人  wangjianjun0730
runloop.png

做了一年多的IOS开发,对IOS和Objective-C深层次的了解还十分有限,大多还停留在会用API的级别,这是件挺可悲的事情。想学好一门语言还是需要深层次的了解它,这样才能在使用的时候得心应手,出现各种怪异的问题时不至于不知所措。废话少说,进入今天的正题。
不知道大家有没有想过这个问题,一个应用开始运行以后放在那里,如果不对它进行任何操作,这个应用就像静止了一样,不会自发的有任何动作发生,但是如果我们点击界面上的一个按钮,这个时候就会有对应的按钮响应事件发生。给我们的感觉就像应用一直处于随时待命的状态,在没人操作的时候它一直在休息,在让它干活的时候,它就能立刻响应。其实,这就是run loop的功劳。

一、线程与run loop


int main(int argc, char *argv[])
{
            @autoreleasepool {


              return UIApplicationMain(argc, argv, nil, NSStringFromClass([appDelegate class]));
           }
  }

重点是UIApplicationMain() 函数,这个方法会为main thread 设置一个NSRunLoop 对象,这就解释了本文开始说的为什么我们的应用可以在无人操作的时候休息,需要让它干活的时候又能立马响应。

NSRunLoop   *runloop = [NSRunLoop currentRunLoop];

来获取到当前线程的run loop。

- (CFRunLoopRef)getCFRunLoop;

获取对应的CFRunLoopRef类,来达到线程安全的目的。

 BOOL isRunning = NO;
      do {
            isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDatedistantFuture]];
     } while (isRunning);

二、Run loop相关知识点

voidcreatePortSource()
{
    CFMessagePortRef port = CFMessagePortCreateLocal(kCFAllocatorDefault, CFSTR("com.someport"),myCallbackFunc, NULL, NULL);
    CFRunLoopSourceRef source =  CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, port, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
    while (pageStillLoading) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        CFRunLoopRun();
        [pool release];
    }
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
}
voidcreateCustomSource()
{
    CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
    CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    while (pageStillLoading) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        CFRunLoopRun();
        [pool release];
    }
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
}
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)argwaitUntilDone:(BOOL)wait modes:(NSArray *)array;
方法一:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:4.0
                                                     target:self
                                                   selector:@selector(backgroundThreadFire:) userInfo:nil
                                                    repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timerforMode:NSDefaultRunLoopMode];

方法二:

[NSTimer scheduledTimerWithTimeInterval:10
                                        target:self
                                       selector:@selector(backgroundThreadFire:)
                                       userInfo:nil
                                       repeats:YES];

1.  Runloop入口
2.  Runloop何时处理一个定时器
3.  Runloop何时处理一个输入源
4.  Runloop何时进入睡眠状态
5.  Runloop何时被唤醒,但在唤醒之前要处理的事件
6.  Runloop终止

和定时器类似,在创建的时候你可以指定run loop观察者可以只用一次或循环使用。若只用一次,那么在它启动后,会把它自己从run loop里面移除,而循环的观察者则不会。定义观察者并把它添加到run loop,只能使用Core Fundation。下面的例子演示了如何创建run loop的观察者:

- (void)addObserverToCurrentRunloop
{
    // The application uses garbage collection, so noautorelease pool is needed.
    // Create a run loop observer and attach it to the runloop.
    CFRunLoopObserverContext  context = {0, self, NULL, NULL, NULL};
    CFRunLoopObserverRef    observer =CFRunLoopObserverCreate(kCFAllocatorDefault,
                                                              kCFRunLoopBeforeTimers, YES, 0, &myRunLoopObserver, &context);

    if (observer)
    {
        CFRunLoopRef    cfLoop = [myRunLoop getCFRunLoop];
       CFRunLoopAddObserver(cfLoop, observer, kCFRunLoopDefaultMode);
    }
}

其中,kCFRunLoopBeforeTimers表示选择监听定时器触发前处理事件,后面的YES表示循环监听。


通知观察者run loop已经启动
通知观察者任何即将要开始的定时器
通知观察者任何即将启动的非基于端口的源
启动任何准备好的非基于端口的源
如果基于端口的源准备好并处于等待状态,立即启动;并进入步骤9。
通知观察者线程进入休眠
将线程置于休眠直到任一下面的事件发生:
某一事件到达基于端口的源
定时器启动
Run loop设置的时间已经超时
run loop被显式唤醒
通知观察者线程将被唤醒。
处理未处理的事件
如果用户定义的定时器启动,处理定时器事件并重启run loop。进入步骤2
如果输入源启动,传递相应的消息
如果run loop被显式唤醒而且时间还没超时,重启run loop。进入步骤2
通知观察者run loop结束。

上一篇 下一篇

猜你喜欢

热点阅读