2011-09-28 79 views
-1

我是新來的目標c。我正在使用以下代碼在目標c中執行命令行API。代碼對我來說工作正常。但爲什麼這段代碼使用NSRunLoop?命令行API和waitForDataInBackgroundAndNotify

-(void)uploadData 
{ 
setenv([@"PASSWORD" UTF8String], [mPassword UTF8String], 1); 
[task setLaunchPath:executablePathRoot]; 
[task setArguments:array]; 
NSPipe *pipe = [NSPipe pipe]; 
NSPipe *errorPipe = [NSPipe pipe]; 
[task setStandardOutput:pipe]; 
[task setStandardError:errorPipe]; 
//keeps your log where it belongs 
//[task setStandardInput:[NSPipe pipe]]; 

NSFileHandle *outFile = [pipe fileHandleForReading]; 
NSFileHandle *errFile = [errorPipe fileHandleForReading]; 


[task launch]; 
[[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(terminated:) 
              name:NSTaskDidTerminateNotification 
              object:task]; 

[[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(outData:) 
              name:NSFileHandleDataAvailableNotification 
              object:outFile]; 

[[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(errData:) 
              name:NSFileHandleDataAvailableNotification 
              object:errFile]; 


[outFile waitForDataInBackgroundAndNotify]; 
[errFile waitForDataInBackgroundAndNotify]; 
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 
while(!terminated) 
{ 
    if (![[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) 
    { 
     break; 
    } 
    [pool release]; 
    pool = [[NSAutoreleasePool alloc] init]; 
} 
[pool release]; 

[self appendDataFrom:outFile to:output]; 
[self appendDataFrom:errFile to:error]; 
//[task waitUntilExit]; 
[task release]; 
} 


-(void) outData: (NSNotification *) notification 
{ 
NSLog(@"outData"); 
NSFileHandle *fileHandle = (NSFileHandle*) [notification object]; 
[self appendDataFrom:fileHandle to:output]; 
[fileHandle waitForDataInBackgroundAndNotify]; //Checks to see if data is available in a background thread. 
} 


-(void) errData: (NSNotification *) notification 
{ 
NSLog(@"errData"); 
NSFileHandle *fileHandle = (NSFileHandle*) [notification object]; 
[self appendDataFrom:fileHandle to:output]; 
[fileHandle waitForDataInBackgroundAndNotify]; 
} 

- (void) terminated: (NSNotification *)notification 
{ 
NSLog(@"Task terminated"); 
[[NSNotificationCenter defaultCenter] removeObserver:self]; 
terminated =YES; 
} 

回答

4

這是爲了使uploadData方法同步。執行不能退出while循環,直到terminated標誌設置爲YES。以下致電

[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] 

允許應用程序處理其他事件。所以,當NSTaskDidTerminateNotification收到終止標誌將被改變,while循環結束。

但是,這裏不需要分配autorelease池。而且,代碼過多。它可以簡單得多:

while(!terminated) 
{ 
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
} 

更新:考慮到ughoavgfhw的意見,讓我們撥打電話甚至包括runMode的結果更安全:beforeDate:進入狀態。

while(!terminated && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); 
+1

我不同意你對運行循環代碼的修改。你應該總是在運行循環周圍使用自動釋放池,因爲你永遠不知道在迭代中將創建多少數據並自動釋放。如果'runMode:beforeDate:'返回'NO',因爲它指示了一個錯誤(或者沒有輸入源,這是一個錯誤,因爲管道應該連接到它),所以中斷循環也是適當的。 – ughoavgfhw

+0

@ughoavgfhw我同意如果我們知道我們要優化什麼,那麼可以在那裏使用自動釋放池。但是,我認爲,我們不應該總是把它用作預防手段,因爲我們不知道會創建多少數據。我們已經在當前線程中有一個autorelease池,它會完成這項工作。 – Davyd

+0

@ughoavgfhw我同意,應該處理runMode:beforeDate的負面結果。 – Davyd