2014-02-27 171 views
0

我正在測試標準運行循環(由XCode創建)應用程序。我的應用有2個按鈕:
運行循環不會繼續事件

  1. Start Loop - 在某些模式下啓動runloop(見下面的代碼);
  2. Stop Loop - 更改self.stop標誌停止runloop。

`

- (IBAction)stopLoop:(id)sender 
{ 
    self.stop = YES; 
} 

- (IBAction)startLoop:(id)sender 
{ 
    self.stop = NO; 
    do 
    { 
     [[NSRunLoop currentRunLoop] runMode:runLoopMode beforeDate:runLoopLimitDate]; 
     if (self.stop) 
     { 
      break; 
     } 
    } while (YES); 
} 

`

其中:
1. runLoopMode是預定義模式(I嘗試每個,默認情況下,事件跟蹤,莫代爾,連接)中的一個。
2. runLoopLimitDate [NSDate distantFuture]或[NSDate distantPast]或關閉功能。
3. self.stop標誌被安裝在按鈕調用的其他方法中。

就是這樣,我的應用程序沒有任何其他代碼。

AFAIU,runloop模式是一組事件源。所以,如果我在某種模式下運行runloop,runloop將會繼續那些與這種模式相關的事件源。
默認情況下,Cocoa在默認模式下運行runloop,並且所有事件都會大幅度進行。但是當用戶按下startLoop按鈕時,我的應用凍結:
freezed app
startLoop方法永遠不會打破這個無限循環。應用程序不會向我發送任何事件,因此UI凍結並且用戶無法按stopLoop按鈕。如果我運行Core Foundation對應項,也會出現同樣的問題。

,當我嘗試接收通過的NSApplication方法nextEventMatchingMask:untilDate:inMode:dequeue:(的NSWindow)事件,並通過相同模式,我收到UI事件。

- (IBAction)startLoop:(id)sender 
{ 
    self.stop = NO; 
    do 
    { 
     NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSEventTrackingRunLoopMode dequeue:YES]; 
     if (event == nil) 
     { 
      break; 
     } 
     [NSApp sendEvent:event]; 
     if (self.stop) 
     { 
      break; 
     } 
    } while (YES); 
} 

有問題:「爲什麼?如果我跑默認的運行循環模式,或者一些其他的,這樣,我不能接受的事件」
感謝您的建議。

+0

你可能需要澄清你到底在做什麼。例如,如果其他方法從不設置self.stop,會發生什麼? – Volker

+0

謝謝,我更新了我的問題。 – Lexandr

+0

您只是以這種方式阻止了runloop,限制日期意味着在此之前runloop被阻止。您的循環會立即重置,從而再次阻塞。停止按鈕永遠不會發生更改以發送其操作。你想實現什麼? – Volker

回答

0

如果在應用中將以下代碼替換爲-startLoop:方法,會發生什麼情況?

- (NSString *) debugLogRunLoopInfo(BOOL didRun) 
{ 
    NSLog (@"didRun? %@, runMode: %@, dateNow: %@, limitDate: %@", 
     didRun ? @"YES" : @"NO", 
     runLoopMode, 
     [NSDate date], 
     limitDate); 
} 

- (IBAction)startLoop:(id)sender 
{ 
    BOOL didRun = NO; 
    do 
    { 
     didRun = [[NSRunLoop currentRunLoop] runMode:runLoopMode beforeDate:runLoopLimitDate]; 
     [self debugLogRunLoopInfo:didRun]; 
     if (self.stop) 
     { 
      break; 
     } 
    } while (YES); 
} 
+0

didRun = YES; currentMode = nil; limitDate = 2014年2月27日2時01分54秒послеполудня+0000(我跑我的應用程序在16:03) – Lexandr

+1

圍棋與沃爾克的建議之上:-runUntilDate:會做你希望做什麼。 –

+0

我在上面我建議的代碼中修復了一個令人尷尬的錯誤。您可以再次嘗試我的代碼,但最終,您將要使用'-runUntilDate:'方法代替'-runMode:beforeDate:' –

0

-[NSRunLoop runUntilDate:]該方法在旋轉的NSDefaultRunLoopMode runloop。既然你想嘗試runloop模式,你可以嘗試下面的代碼。

我已經實現了一個-myRunLoopUntilDate:runMode:方法,該方法記錄了runUntilDate:的記錄,但允許您指定runloop模式。

所有這些都是在我的文本編輯器中編譯的(即根本不編譯),所以要注意空出來。

- (NSString *) debugLogRunLoopInfo(BOOL didRun) 
{ 
    NSLog (@"didRun? %@, runMode: %@, dateNow: %@, limitDate: %@", 
     didRun ? @"YES" : @"NO", 
     runLoopMode, 
     [NSDate date], 
     limitDate); 
} 

- (void) myRunLoopUntilDate:(NSDate *)limitDate runMode:(NSString *)runLoopMode 
{ 
    BOOL didRun = NO; 
    do { 
     didRun = [[NSRunLoop currentRunLoop] runMode:runLoopMode beforeDate:limitDate]; 
     [self debugLogRunLoopInfo:didRun]; 
    } while (didRun && ([limitDate timeIntervalSinceNow] > 0)); 
} 

- (IBAction)startLoop:(id)sender 
{ 
    BOOL didRun = NO; 
    do 
    { 
     [self myRunLoopUntilDate:runLimitDate runMode:runLoopMode]; 
     if (self.stop) 
     { 
      break; 
     } 
    } while (YES); 
} 
1

您假定在NSDefaultRunMode運行NSRunLoop處理用戶輸入事件,如按鍵或鼠標點擊。我不認爲是這樣。

的NSApplication獲取從nextEventMatchingMask:untilDate:inMode:dequeue:事件的事件。通過運行這樣的運行循環,你不會真的獲取事件隊列的任何事件。

雲嘗試是這樣的:

- (IBAction)startLoop:(id)sender 
{ 
    do 
    { 
     NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask]; 
     [NSApp sendEvent:event]; 

     if (self.stop) 
     { 
      break; 
     } 
    } while (YES); 
} 

(沒有測試)。

+0

是的,謝謝,這種方法可行(也適用於其他模式,這是我的錯誤,我不寫這個代碼到最初的問題,我會),但我很有趣的另一個:爲什麼運行循環模式不派遣'UI'事件給我,當'nextEventMatchingMask:untilDate:inMode:dequeue :'用相同的模式呢? – Lexandr

+0

自身運行的NSRunLoop不取從應用程序的事件隊列(見[事件指派](https://developer.apple.com/librarY/mac/documentation/Cocoa/Conceptual/EventOverview/EventArchitecture/EventArchitecture任何事件。 html#// apple_ref/doc/uid/10000060i-CH3-SW4)你應該看看'nextEventMatchingMask:untilDate:inMode:dequeue:'作爲比NSRunLoop更高級別的API。 – pfandrade