runloop

现在说说runloop为何会成为cocoa开发中迷惑的点。因为很多新手没有从动态角度看它。 首先回想一下第2点介绍的runtime的概念。 接着我出一个题思考一下。 
 
现在我有一个程序片段如下: 
复制代码
  1. - (void)myThread:(id)sender
  2. {
  3.     NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
  4.     while (TRUE) {
  5.         
  6.         //do some jobs
  7.        //break in some condition
  8.         
  9.         usleep(10000);
  10.         
  11.         [pool drain];
  12.     }
  13.     
  14.     [pool release];
  15. }
 
现在要求,做某些设计,使得当这个线程运行的同时,还可以从其它线程里往它里面随意增加或去掉不同的计算任务。 这,就是NSRunloop的最原始的开发初衷。让一个线程的计算任务更加灵活。 这个功能在c, c++里也许可以做到但是非常难,最主要的是因为语言能力的限制,以前的程序员很少这么去思考。 
 
好,现在我们对上面代码做一个非常简单的进化: 
 
复制代码
  1. NSMutableArray *targetQueue;
  2. NSMutableArray *actionQueue;

  3. - (void)myThread:(id)sender
  4. {
  5.     NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
  6.     while (TRUE) {
  7.         
  8.         //do some jobs
  9.         //break in some condition
  10.         int n=[targetQueue count];
  11.         assert(n==[actionQueue count]);
  12.         for(int i=0;i<n;i++){
  13.             id target=[targetQueue objectAtIndex:i];
  14.             SEL action=NSSelectorFromString([actionQueue objectAtIndex:i]);
  15.             if ([target respondsToSelector:action]) {
  16.                 [target performSelector:action withObject:nil];
  17.             }
  18.         }
  19.                 
  20.         usleep(10000);
  21.         
  22.         [pool drain];
  23.     }
  24.     
  25.     [pool release];
  26. }
 
注意,这里没有做线程安全处理,记住Mutable container is not thread safe. 
这个简单的扩展,让我们看到了如何利用runtime能力让线程灵活起来。当我们从另外线程向targetQueue和actionQueue同时加入对象和方法时候,这个线程函数就有了执行一个额外代码的能力。 
 
但,有人会问,哪里有runloop? 那个是 nsrunloop? 看不出来啊。 
复制代码
  1. while (TRUE) {
  2. //break in some condition
  3. }
 
一个线程内这个结构就叫线程的runloop,   它和NSRunloop这个类虽然名字很像,但完全不是一个东西。以前在使用静态语言开始时候,程序员没有什么迷惑,因为没有NSRunloop这个东西。 我接着来说,这个NSRunloop是如何来得。 
 
第二段扩展代码里面确实没有NSRunloop这个玩意儿,我们接着做第3次改进。 这次我们的目的是把其中动态部分抽象出来。 
 
复制代码

  1. @interface MyNSTimer : NSObject
  2. {
  3.   id target;
  4.   SEL action;
  5.   float interval;
  6.   CFAbsoluteTime lasttime;
  7. }
  8. - (void)invoke;
  9. @end

  10. @implementation MyNSTimer
  11. - (void)invoke;
  12. {
  13.   if ([target respondsToSelector:action]) {
  14.         [target performSelector:action withObject:nil];
  15.     }
  16. }
  17. @end
 
 
 
复制代码
  1. @interface MyNSRunloop : NSObject
  2. {
  3.   NSMutableArray *timerQueue;
  4. }
  5. - (void)addTimer:(MyNSTimer*)t;
  6. - (void)executeOnce;
  7. @end

  8. @implementation MyNSRunloop
  9. - (void)addTimer:(MyNSTimer*)t;
  10. {
  11.   @synchronized(timerQueue){
  12.       [timerQueue addObject:t];
  13.     }
  14. }
  15. - (void)executeOnce;
  16. {
  17.   CFAbsoluteTime currentTime=CFAbsoluteTimeGetCurrent();
  18.   @synchronized(timerQueue){
  19.       for(MyNSTimer *t in timerQueue){
  20.           if(currentTime-t.lasttime>t.interval){
  21.               t.lasttime=currentTime;
  22.                   [t invoke];
  23.           }
  24.       }
  25.   }
  26. }
  27. @end
 
 
复制代码
  1. @interface MyNSThread : NSObject
  2. {
  3.   MyNSRunloop *runloop;
  4. }
  5. - (void)main:(id)sender;
  6. @end

  7. @implementation MyNSThread
  8. - (void)main:(id)sender
  9. {
  10.     NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
  11.     while (TRUE) {
  12.         //do some jobs
  13.         //break in some condition
  14.         [runloop executeOnce];
  15.         usleep(10000);
  16.         [pool drain];
  17.     }
  18.     [pool release];
  19. }
  20. @end
 
 
走到这里,我们就算是基本把Runloop结构抽象出来了。例如我有一个MyNSThread实例,myThread1。我可以给这个实例的线程添加需要的任务,而myThread1内部的MyNSRunloop对象会管理好这些任务。 
 
复制代码
  1. MyNSTimer *timer1=[MyNSTimer scheduledTimerWithTimeInterval:1
  2.                                                    target:obj1
  3.                                                  selector:@selector(download1:)];
  4. [myThread1.runloop addTimer:timer1];

  5. MyNSTimer *timer2=[MyNSTimer scheduledTimerWithTimeInterval:2
  6.                                                    target:obj2
  7.                                                  selector:@selector(download2:)];
  8. [myThread1.runloop addTimer:timer2];
 
 
当你看懂了上面的代码也许会感叹,‘原来是这么回事啊!为什么把这么简单的功能搞这么复杂呢?’ 其实就是这么回事,把Runloop抽象出来可以使得线程任务管理更加loose coupling,给设计模式提供更大的空间。这样第三方开发者不需要过深入的涉及线程内部代码而轻松管理线程任务。另外请注意,这里MyNSRunloop, MyNSTimer等类是我写得一个模拟情况,真实的NSRunloop实现肯定不是这么简单。这里只为了说明一个思想。这种思想贯穿整个cocoa framework从界面更新到event管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值