2010-06-17 22 views
2

我在用Interface Builder設計的GUI編寫Cocoa應用程序。我需要在不阻塞UI調度後臺活動(定期),所以我在一個單獨的線程中運行它,就像這樣:在不同的NSThread/NSRunLoop中運行和管理NSTimer

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 
    [self performSelectorInBackground:@selector(schedule) withObject:nil]; 
} 

- (void) schedule { 
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 
    NSRunLoop* runLoop = [NSRunLoop currentRunLoop]; 

    timer = [[NSTimer scheduledTimerWithTimeInterval:FEED_UPDATE_INTERVAL 
                target:activityObj 
             selector:@selector(run:) 
             userInfo:nil 
             repeats:YES] 
     retain]; 

    [runLoop run]; 
    [pool release]; 
} 

我保留了計時器,所以我可以很容易地無效並重新安排。

問題:爲響應GUI事件,我還必須觸發run:方法,因此它是同步的(即「執行活動」按鈕)。像這樣:

[timer fire]; 

我也可以用performSelectorInBackground來做到這一點,當然也不會阻塞UI。但是這個同步發射在另一個runloop中運行!所以我不能保證它們不會重疊。我怎樣才能將所有的發射排列在同一個runloop上?

回答

0
[timer setFireDate:[NSDate distantPast]]; 

我通過調節下一個火情日期爲儘快,通過使過去的日期到setFireDate獲得期望的效果。

0

您可以使用經典的併發解決方案:信號量。在你的情況下,最簡單的方法是使用@synchronized指令。將run:方法的整個身體(或至少是敏感部分)與@synchronized環繞。對於同步對象,我建議您使用特定的ivar或靜態變量而不是activityObj的類來避免死鎖。

-(void)run:(id)param { 
    // do thread-safe things here 
    @synchronized(syncObj) { 
     // put your critical section here 
    } 
    // do more thread-safe things here 
} 

關鍵部分的代碼不會重疊。

0

你應該在mainThread上調度NSTimer(並且啓動定時器來執行選擇器---選擇器可以在後臺線程上執行,因此不會阻塞UI),而不是通過GCD在後臺線程上調度NSTimer,因爲NSTimer將被添加到NSRunLoop中,並且每個NSRunLoop都與一個NSTread相關聯。因此,當使用GCD時,請使用dispatch_after而不是NSTimer來延遲發生的事情。