读书人

iOS运作回路(RunLoop)总结

发布时间: 2013-06-25 23:45:41 作者: rapoo

iOS运行回路(RunLoop)总结

转自:http://www.cocoachina.com/iphonedev/sdk/2011/1111/3487.html

?

首先看两个runloop的示例,来源:http://paste.lisp.org/display/86524

第一个:

?

  1. #include?<CoreFoundation/CoreFoundation.h>??
  2. ??
  3. static?void??
  4. _perform(void?*info?__unused)??
  5. {??
  6. ????printf("hello\n");??
  7. }??
  8. ??
  9. static?void??
  10. _timer(CFRunLoopTimerRef?timer?__unused,?void?*info)??
  11. {??
  12. ????CFRunLoopSourceSignal(info);??
  13. }??
  14. ??
  15. int??
  16. main()??
  17. {??
  18. ????CFRunLoopSourceRef?source;??
  19. ????CFRunLoopSourceContext?source_context;??
  20. ????CFRunLoopTimerRef?timer;??
  21. ????CFRunLoopTimerContext?timer_context;??
  22. ??
  23. ????bzero(&source_context,?sizeof(source_context));??
  24. ????source_context.perform?=?_perform;??
  25. ????source?=?CFRunLoopSourceCreate(NULL,?0,?&source_context);??
  26. ????CFRunLoopAddSource(CFRunLoopGetCurrent(),?source,?kCFRunLoopCommonModes);??
  27. ??
  28. ????bzero(&timer_context,?sizeof(timer_context));??
  29. ????timer_context.info?=?source;??
  30. ????timer?=?CFRunLoopTimerCreate(NULL,?CFAbsoluteTimeGetCurrent(),?1,?0,?0,?
  31. ? ? _timer,?&timer_context);??
  32. ????CFRunLoopAddTimer(CFRunLoopGetCurrent(),?timer,?kCFRunLoopCommonModes);??
  33. ??
  34. ????CFRunLoopRun();??
  35. ??
  36. ????return?0;??
  37. }??

?

?

第二个:

?

  1. #include?<dispatch/dispatch.h>??
  2. #include?<stdio.h>??
  3. ??
  4. int??
  5. main()??
  6. {??
  7. ????dispatch_source_t?source,?timer;??
  8. ??
  9. ????source?=?dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD,?0,?0,
  10. ? ? dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0));??
  11. ????dispatch_source_set_event_handler(source,?^{??
  12. ????????printf("hello\n");??
  13. ????});??
  14. ????dispatch_resume(source);??
  15. ??
  16. ????timer?=?dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,?0,?0,?
  17. ? ? dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0));??
  18. ????dispatch_source_set_timer(timer,?DISPATCH_TIME_NOW,?1ull?*?NSEC_PER_SEC,?0);??
  19. ????dispatch_source_set_event_handler(timer,?^{??
  20. ????????dispatch_source_merge_data(source,?1);??
  21. ????});??
  22. ????dispatch_resume(timer);??
  23. ??
  24. ????dispatch_main();??
  25. }??

?

功能是向main线程中加入两个input source,一个是timer,一个是自定义input source,然后这个timer中触发自定义source,于是调用其回调方法。 在这儿timer触发source来调用回调方法,显得有点多此一举。但是在多线程开发当中,这就很有用了,我们可以把这个自定义的source加入到子线程的runloop中,然后在主线程中触发source,这样在子线程中就可以调用回调方法了。 ?这样做的好久是什么呀? 节约用电,因为runloop一般情况下是休眠的,只有事件触发的时候才开始工作。 这与windows下的waitforsingleobject有点类似, 与多线程中的信号量,事件也有些雷同。

?

上面说到的input source(输入源例)到底是什么呢?输入源样例可能包括用户输入设备(如点击button)、网络链接(socket收到数据)、定期或时间延迟事件(NSTimer),还有异步回调(NSURLConnection的异步请求)。然后我们对其进行了分类,有三类可以被runloop监控,分别是sources、timers、observers。

在苹果文档中对runloop有详细介绍,下面参考中有中文版。那文档中的代码关于NSPort的部份在iOS上是不行的,不过可以用其CF方法实现,在我的demo中有展示。

?

每一个线程都有自己的runloop, 主线程是默认开启的,创建的子线程要手动开启,因为NSApplication 只启动main applicaiton thread。

没有source的runloop会自动结束。

事件由NSRunLoop 类处理。

RunLoop监视操作系统的输入源,如果没有事件数据, 不消耗任何CPU 资源。

如果有事件数据,run loop 就发送消息,通知各个对象。

用 currentRunLoop 获得 runloop的 reference

给 runloop 发送run 消息启动它。

?

?

文档中介绍下面四种情况是使用runloop的场合:

?1.使用端口或自定义输入源和其他线程通信

?2.子线程中使用了定时器

?3.cocoa中使用任何performSelector到了线程中运行方法

?4.使线程履行周期性任务,(我把这个理解与2相同)

如果我们在子线程中用了NSURLConnection异步请求,那也需要用到runloop,不然线程退出了,相应的delegate方法就不能触发。

解决的方法参看:

http://www.cocoabyss.com/foundation/nsurlconnection-synchronous-asynchronous/

http://www.wim.me/nsurlconnection-in-its-own-thread/

?

参考:

http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html

http://www.wim.me/nsurlconnection-in-its-own-thread/

http://xubenyang.me/384

http://iphonedevelopmentbits.com/event-driven-multitasking-runloopssymbian-ios

读书人网 >操作系统

热点推荐