2011-12-21 29 views
14

我有一個NSRunLoop對象,我附加了定時器和流。它效果很好。停止它是另一回事。CFRunLoopRun()與[NSRunLoop運行]

我使用[runLoop run]運行循環。

如果我嘗試使用CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop])來停止循環,則循環不會停止。如果我使用CRunLoopRun()來啓動循環,它會起作用。我也確定調用是在正確的線程(運行我的自定義運行循環的線程)上進行的。我已用pthread_self()進行調試。

我發現一個郵件列表存檔,開發人員說:「如果您使用NSRunLoop的運行方法啓動循環,請不要打擾使用CRunLoopStop()」。我可以理解爲什麼它是這樣的 - 你通常將來自同一組函數的初始化器和終結器配對。

如何在沒有「訴諸CF」的情況下停止NSRunLoop?我沒有在NSRunLoop上看到stop方法。該文檔說,你可以通過三種方式停止運行循環:

  1. 配置運行循環與超時值運行
  2. 告訴運行循環停止使用CFRunLoopStop()
  3. 刪除所有輸入源,但這是一種不可靠的方式來停止運行循環,因爲你永遠不知道什麼卡什麼成揹着你

好運行循環,我已經嘗試過2和有一個「醜」的感覺,因爲你必須深入研究CF. 3.是不可能的 - 我不喜歡非確定性代碼。

這給我們留下了1.如果我正確理解了文檔,您不能將「超時」添加到已存在的運行循環中。您只能在超時運行新的運行循環。如果我運行一個新的運行循環,它不會解決我的問題,因爲它只會創建一個嵌套的運行循環。我仍然會彈回舊的,我也想阻止......對吧?我可能誤解了這一個。另外,我不想用超時值運行循環。如果我這樣做,我必須在燃燒CPU週期(低超時值)和響應性(高超時值)之間進行權衡。

這是建立我現在(僞代碼-ISH):

Communicator.h

@interface Communicator : NSObject { 
    NSThread* commThread; 
} 

-(void) start; 
-(void) stop; 
@end 

Communicator.m

@interface Communicator (private) 
-(void) threadLoop:(id) argument; 
-(void) stopThread; 
@end 

@implementation Communicator 
-(void) start { 
    thread = [[NSThread alloc] initWithTarget:self 
            selector:@selector(threadLoop:) 
             object:nil]; 
    [thread start]; 
} 

-(void) stop { 
    [self performSelector:@selector(stopThread) 
       onThread:thread 
       withObject:self 
      waitUntilDone:NO]; 
    // Code ommitted for waiting for the thread to exit... 
    [thread release]; 
    thread = nil; 
} 
@end 

@implementation Communicator (private) 
-(void) stopThread { 
    CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]); 
} 

-(void) threadLoop:(id) argument { 
    // Code ommitted for setting up auto release pool 

    NSRunLoop* runLoop = [NSRunLoop currentRunLoop]; 

    // Code omitted for adding input sources to the run loop 

    CFRunLoopRun(); 
    // [runLoop run]; <- not stoppable with 

    // Code omitted for draining auto release pools 

    // Code omitted for signalling that the thread has exited 
} 
@endif 

我是什麼去做? CF常見/好的模式?我不太瞭解基金會。干擾CF層可能是危險的(關於內存破壞,不一致性,內存泄漏)?有沒有更好的模式來實現我想要實現的目標?

回答

7

你做得很好。如果您無法實現基金會的目標,那麼使用CoreFoundation並沒有問題。由於CoreFoundation爲C,因此更容易搞亂內存管理,但在使用CFRunLoop而不是NSRunLoopsometimes it may even be saferCFRunLoop API是線程安全的,而NSRunLoop不是)時沒有內在危險。

如果你想停止你的NSRunLoop,你可以使用runMode:beforeDate:來運行它。 runMode:beforeDate:在處理輸入源後立即返回,因此您無需等到達到超時日期。

NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
NSDate *date = [NSDate distantFuture]; 
while (!runLoopIsStopped && [runLoop runMode:NSDefaultRunLoopMode beforeDate:date]); 

然後,停止運行循環,你只需要設置runLoopIsStoppedYES

+0

啊,聰明!我沒有看到'runMode'只運行一次。通過反覆啓動運行循環會產生顯着的性能損失嗎? – 2011-12-21 15:30:41

+0

不,不存在:' - [NSRunLoop運行]'和' - [NSRunLoop runUntilDate:]'是如何工作的。 – 2011-12-21 16:13:41

+1

如果您只將runLoopIsStopped設置爲YES,線程將不會停止。 您需要將其設置爲YES並對該runloop的線程執行操作,否則[runLoop runMode:NSDefaultRunLoopMode beforeDate:date]不會退出。 這花了我很長時間才弄清楚。 – Pada 2012-06-27 10:57:25