2012-02-13 61 views
0

我真的很苦惱與多線程程序,當外部變量更改時更改IBOutlet。使用多線程訪問UIcomponents

帶班頭:

@interface QuestionViewController : UIViewController{ 

// IBOutlet 
IBOutlet UIBarButtonItem *changeButton; 

... 

} 

啓動線程:

// Starts new thread with method 'statusPollMethod' to determine when status 
    [NSThread detachNewThreadSelector:@selector(statusPollMethod:) toTarget:self withObject: @"Voting"]; 

開始:

-(void)statusPollMethod:requiredStatus{ 

GetSessionDataApi *statusPoll = [GetSessionDataApi new]; 
SessionCache *tempSessionCache = [SessionCache new]; 

... 

@synchronized(self){ 
// Infinite Loop 
while(1) { 

    // If sessionStatus is 'Voting' set button as displayed 
    if ([[tempSessionCache sessionStatus] isEqualToString: (@"Voting")]){ 
     NSLog(@"Status is Voting!"); 
     // Ungreys and sets the button 
     [changeButton setTitle:@"Submit"]; 
      changeButton.enabled = YES; 
    } 

    // Wait for around 3 seconds 
    [NSThread sleepForTimeInterval:3]; 

    } 
    } 
    return; 
} 

的問題是,第二個線程只是偶爾完成對IBOutlet中的任何行動。 IBOutlet也被第一個線程訪問,所以我知道我可能有一些多線程問題,我不確定如何保護IBOutlet免受此影響。

建議我已經瀏覽過Apple Docs/Overflow帖子,但我仍然感到困惑。

我真的很感謝你的幫忙!

Tim

+0

是你的問題是不執行下面的LOC - [changeButton setTitle:@「Submit」]; changeButton.enabled = YES; – rishi 2012-02-13 16:51:04

回答

1

UI組件不是線程安全的。主線程使用運行循環(請參閱NSRunLoop)調出代碼(更改UI狀態的位置),然後更新循環中每次傳遞的屏幕。從任何其他線程混淆UI組件都會搞砸了。

您需要將改變按鈕標題/啓用的代碼放在單獨的方法中,並通知主線程調用它。你可以用performSelectorOnMainThread:withObject:waitUntilDone:來做到這一點。這基本上創建了一個單一使用的NSTimer,並調度它在主線程的運行循環中立即觸發,所以主線程會盡快調用該方法。

您可以選擇暫停第二個線程,直到主線程完成調用(waitUntilDone:)。如果你只是更新UI狀態,我建議不要等待,因爲你不需要任何信息從UI傳回給你的工作線程。

+0

完美運作,非常感謝!不確定我如何處理沒有溢出.... – 2012-02-13 19:42:51

1

您是否試過performSelectorOnMainThread?

[self performSelectorOnMainThread:@selector(doUIOnMainThread) withObject:nil waitUntilDone:NO]; 

然後我的方法doUIOnMainThread做的UI事情。