2011-11-28 94 views
3

從我的主線程我請使用NSTask塊主線程

[self performSelectorInBackground:@selector(startTask) withObject:nil]; 

這是該方法startTask一個選擇器:

-(void)startTask{  
    NSTask *task = [[NSTask alloc] init]; 
    NSPipe *pipe = [[NSPipe alloc] init]; 
    NSFileHandle *fh = [pipe fileHandleForReading]; 

    NSArray *args = [NSArray arrayWithObjects:@"-z",iPAddress, [NSString stringWithFormat:@"%@",portNumber], nil]; 

    [task setLaunchPath:@"/usr/bin/nc"]; 
    [task setArguments:args]; 
    [task setStandardOutput:pipe]; 

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
    [nc removeObserver:self]; 
    [nc addObserver:self 
      selector:@selector(dataReady:) 
       name:NSFileHandleReadCompletionNotification 
      object:fh]; 

    [task launch]; 
    [fh readInBackgroundAndNotify]; 
} 

這應該防止NSTask阻塞主線程(以及UI) 。但事實並非如此。 如果我刪除

[task launch]; 

主線程不會被阻止。我究竟做錯了什麼? O_O

(BTW dataReady只是處理數據這不是這種方法,阻止...。)

編輯:我剛剛發現,我不是要求在主線程的選擇。我從一個單獨的線程調用它!不幸的是,我必須從該線程調用它。

+0

看看http://stackoverflow.com/questions/7676508/nstask-blocking-the-main-thread,你的方法似乎在這種情況下工作。 – Damien

+0

請在您的應用程序的示例中,其主線程被阻止並編輯您的問題以包含主線程的堆棧跟蹤。 –

回答

3

我不知道這是回答你的問題,但你有一個根本問題:

readInBackgroundAndNotify文檔說:

你必須從一個線程調用此方法它有一個有效的運行循環。

你不這樣做,因爲startTask是在它自己的線程上,並且你沒有運行一個運行循環。

+0

如果我刪除readInBackgroundAndNotify或沒有關係。問題依然存在。但你是對的。我也應該這樣。我編輯了我的問題!我發現,我沒有從主線程調用選擇器。我從一個單獨的線程調用它! – Daniel

+0

@丹尼爾:是的,這就是JeremyP所說的。 –

+0

我誤解了答案。這確實是解決方案。 – Daniel

3

我不知道是什麼問題,但我建議看看NSOperationQueue。

NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
[queue addOperationWithBlock:^(void) { 
    NSTask *task = [[NSTask alloc] init]; 
    NSPipe *pipe = [[NSPipe alloc] init]; 
    NSFileHandle *fh = [pipe fileHandleForReading]; 

    NSArray *args = [NSArray arrayWithObjects:@"-z",iPAddress, [NSString stringWithFormat:@"%@",portNumber], nil]; 

    [task setLaunchPath:@"/usr/bin/nc"]; 
    [task setArguments:args]; 
    [task setStandardOutput:pipe]; 

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
    [nc removeObserver:self]; 
    [nc addObserver:self 
      selector:@selector(dataReady:) 
       name:NSFileHandleReadCompletionNotification 
      object:fh]; 

    [task launch]; 
}]; 
[queue autorelease]; 

還是讓我知道,如果您有任何疑問

在文檔繼承人上NSOperationQueue一些信息只是如果你想知道:

操作隊列通常會提供用於運行其 操作線程。在Mac OS X v10.6及更高版本中,操作隊列使用libdispatch庫(也稱爲Grand Central Dispatch)啓動 執行其操作。因此,操作始終在獨立線程上執行 ,無論它們是否爲 指定爲併發或非併發操作。

+0

感謝您的回答。儘管我建議將這一行從「[nc removeObserver:self]」更改爲「[nc removeObserver:self name:NSFileHandleReadCompletionNotification」object:fh]「。否則,您將面臨從所有通知中刪除整個實例的危險。 – auco

+0

@auco啊不夠公平,我通常創建一個類來處理所有這些事情,所以我得到的唯一通知就是這些通知。儘管我有錯誤的假設 – DanZimm