iphone開發者筆記7-Iphone開發-NSRunLoop概述和原理

Iphone開發-NSRunLoop概述和原理
1.什麼是NSRunLoop?
我們會經常看到這樣的代碼:

- (IBAction)start:(id)sender
{
pageStillLoading = YES;
[NSThread detachNewThreadSelector:@selector(loadPageInBackground:)toTarget:self withObject:nil];
[progress setHidden:NO];
while (pageStillLoading) {
[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
[progress setHidden:YES];
}
  這段代碼很神奇的,因爲他會“暫停”代碼運行,而且程序運行不會因爲這裏有一個while循環而受到影響。在[progress setHidden:NO]執行之後,整個函數像暫停了一樣,停在循環裏面,等loadPageInBackground裏面的操作都完成了以後,
才讓[progress setHidden:YES]運行。這樣做就顯得簡單,而且邏輯很清晰。如果不這樣做,就需要在loadPageInBackground裏面表示load完成的地方調用[progress setHidden:YES],顯得代碼不緊湊而且容易出錯。
那麼具體什麼是NSRunLoop呢?其實NSRunLoop的本質是一個消息機制的處理模式。如果你對vc++編程有一定了解,在windows中,有一系列很重要的函數SendMessage,PostMessage,GetMessage,
這些都是有關消息傳遞處理的API。但是在你進入到Cocoa的編程世界裏面,我不知道你是不是走的太快太匆忙而忽視了這個很重要的問題,Cocoa裏面就沒有提及到任何關於消息處理的API,
開發者從來也沒有自己去關心過消息的傳遞過程,好像一切都是那麼自然,像大自然一樣自然?在Cocoa裏面你再也不用去自己定義WM_COMMAD_XXX這樣的宏來標識某個消息,

也不用在switch-case裏面去對特定的消息做特別的處理。難道是Cocoa裏面就沒有了消息機制?答案是否定的,只是Apple在設計消息處理的時候採用了一個更加高明的模式,那就是RunLoop。


利用NSRunLoop阻塞NSOperation線程
使用NSOperationQueue簡化多線程開發中介紹了多線程的開發,我這裏主要介紹一下使用NSRunLoop阻塞線程。
主要使用在NStimer定時啓用的任務或者異步獲取數據的情況如socket獲取網絡數據,要阻塞線程,直到獲取數據之後在釋放線程。
下面是線程中沒有使用NSRunLoop阻塞線程的代碼和執行效果:
線程類:

#import <Foundation/Foundation.h> 
@interface MyTask : NSOperation {     

@end
#import "MyTask.h" 
@implementation MyTask 
-(void)main     
{      
    NSLog(@"開始線程=%@",self);      
    [NSTimer timerWithTimeInterval:2 target:self selector:@selector(hiandeTime:) userInfo:nil repeats:NO];      
}      
-(void)hiandeTime:(id)sender      
{      
    NSLog(@"執行了NSTimer");      
}      
-(void)dealloc      
{      
    NSLog(@"delloc mytask=%@",self);      
    [super dealloc];      

@end
線程添加到隊列中:


- (void)viewDidLoad     
{      
    [super viewDidLoad];      
    NSOperationQueue *queue=[[NSOperationQueue alloc] init];      
    MyTask *myTask=[[[MyTask alloc] init] autorelease];      
    [queue addOperation:myTask];      
    MyTask *myTask1=[[[MyTask alloc] init] autorelease];      
    [queue addOperation:myTask1];      
    MyTask *myTask2=[[[MyTask alloc] init] autorelease];      
    [queue addOperation:myTask2];      
    [queue release];      
}

執行結果是:
2011-07-25 09:44:45.393 OperationDemo[20676:1803] 開始線程=<MyTask: 0x4b4dea0>   
2011-07-25 09:44:45.393 OperationDemo[20676:5d03] 開始線程=<MyTask: 0x4b50db0>    
2011-07-25 09:44:45.396 OperationDemo[20676:1803] 開始線程=<MyTask: 0x4b51070>    
2011-07-25 09:44:45.404 OperationDemo[20676:6303] delloc mytask=<MyTask: 0x4b4dea0>    
2011-07-25 09:44:45.404 OperationDemo[20676:5d03] delloc mytask=<MyTask: 0x4b50db0>    
2011-07-25 09:44:45.405 OperationDemo[20676:6303] delloc mytask=<MyTask: 0x4b51070>

可以看到,根本沒有執行NSTimer中的方法,線程就釋放掉了,我們要執行
NSTimer中的方法,就要利用NSRunLoop阻塞線程。下面是修改後的代碼:

-(void)main     
{      
    NSLog(@"開始線程=%@",self);      
    NSTimer *timer=[NSTimer timerWithTimeInterval:2 target:self selector:@selector(hiandeTime) userInfo:nil repeats:NO];      
    [timer fire];      
    while (!didDisconnect) {      
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];      
    }      
}

執行結果如下:
2011-07-25 10:07:00.543 OperationDemo[21270:1803] 開始線程=<MyTask: 0x4d16380>     
2011-07-25 10:07:00.543 OperationDemo[21270:5d03] 開始線程=<MyTask: 0x4d17790>      
2011-07-25 10:07:00.550 OperationDemo[21270:6303] 開始線程=<MyTask: 0x4d17a50>      
2011-07-25 10:07:00.550 OperationDemo[21270:1803] 執行了NSTimer      
2011-07-25 10:07:00.551 OperationDemo[21270:5d03] 執行了NSTimer      
2011-07-25 10:07:00.552 OperationDemo[21270:6303] 執行了NSTimer      
2011-07-25 10:07:00.556 OperationDemo[21270:6503] delloc mytask=<MyTask: 0x4d16380>      
2011-07-25 10:07:00.557 OperationDemo[21270:6303] delloc mytask=<MyTask: 0x4d17790>      
2011-07-25 10:07:00.557 OperationDemo[21270:5d03] delloc mytask=<MyTask: 0x4d17a50>

我們可以使用NSRunLoop進行線程阻塞。


發佈了0 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章