RunLoop in iOS

本文深入解析了NSRunLoop的工作原理及其在iOS开发中的应用。通过具体示例展示了如何利用NSRunLoop进行异步网络请求,并保持UI线程响应性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RunLoop in iOS 

|

A run loop for a given thread will wait until one or more of its input sources has some data or event, then fire the appropriate input handler(s) to process each input source that is "ready." After doing so, it will then return to its loop, processing input from various sources, and "sleeping" if there is no work to do. NSRunLoop is better than sleep because it allows the runloop to respond to events while you wait. If you just sleep your thread your app will block even if events arrive.


其实说的简单点儿,NSRunLoop的本质是一个消息机制的处理模式。系统级的RunLoop所示如下

RunLoop in iOS - 阿迪易 - 又见阿迪易

关于 (BOOL) runMode:(NSString *)mode beforeDate:(NSDate *)date这个方法,具体的参数解释如下:

1. mode指定runloop模式来处理输入源。

2. 当date设置为[NSDate distantFuture](将来,基本不会到达的时间),所以除非处理其他输入源结束,否则永不退出处理暂停的当前处理的流程。


一般情况下,当我们使用NSRunLoop的时候,代码都如下所示:

do {


    [[NSRunLoop currentRunLooprunMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];


while (!done);


在上面的代码中,参数done为NO的时候,当前runloop会一直接收处理其他输入源,处理输入源之后会再回到runloop中等待其他的输入源;除非done为NO,否则当前流程一直再runloop中,我们用下面的一个实例来详细的解释如何使用NSRunLoop。


- (void) downloadImage:(NSString*)url{

    

    _subThreed = [NSThread currentThread];

    

    NSAutoreleasePool *uploadPool = [[NSAutoreleasePool allocinit];

    done = NO;

    

    characterBuffer = [NSMutableData data];

    

    [[NSURLCache sharedURLCacheremoveAllCachedResponses];

    NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURLURLWithString:url]];

    connection = [[NSURLConnection allocinitWithRequest:theRequest delegate:self];

        

    if (connection != nil) {

        do {

            [[NSRunLoop currentRunLooprunMode:NSDefaultRunLoopMode beforeDate:[NSDatedistantFuture]]; 

        } while (!done);

    }

    

    imageView.image = [UIImage imageWithData:characterBuffer];

            

    // Release resources used only in this thread.

    connection = nil;

    [uploadPool release];

    uploadPool = nil;

    _subThreed = nil;

}


上面这段代码特别有意思的地方在于,当实例化一个connection之后,马上执行download图片的代理事件,同时当前进程进NSRunLoop,在这个过程中,可以响应某些输入源,比如操作界面上的控件:点击某个button,滑动等等事件,这些事件都可以顺利执行。直到done为YES的时候,这个NSRunLoop才会结束(在具体的代码中,我们可以在connection的didFailWithError 或者connectionDidFinishLoading代理事件中设置),结束NSRunLoop后, 代码会继续执行下面一行:


imageView.image = [UIImage imageWithData:characterBuffer];


下面是代码在NSRunLoop中处理外部输入源的时候callstack,我们可以清楚的看见这里比较明显的有两个thread,其中之一是NSRunLoop(thread 13),而另外的一个是外部输入源的thread(thread 1)。


RunLoop in iOS - 阿迪易 - 又见阿迪易


所以说到这里,我的理解是上面的NSRunLoop代码和异步网络访问比较类似,不同点在于NSRunLoop在connection结束后会重设循环条件,这样就结束NSRunLoop的运行,然后NSRunLoop后面的代码就继续执行,而异步网络访问则需要在connection的connectionDidFinishLoading里面执行后续的代码。为什么这样做呢,其实道理很简单,为了让整个代码的逻辑更加清楚,如果我们没有这样的一个runloop的话,就不得不在子线程的结束的地方,加上imageView.image = [UIImage imageWithData:characterBuffer];(这个有可能是界面操作),则显得代码不够紧凑,容易出错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值