2011-04-29 51 views
2

這裏的問題:我有一些代碼,是這樣的的NSTextField等待,直到一個循環結束更新

otherWinController = [[NotificationWindowController alloc] init]; 
for (int i = 0; i < 10; i++) { 
    [otherWinController showMessage:[NSString stringWithFormat:@"%d", i]]; 
    NSLog(@"%d", i); 
    sleep(1); 
} 

其中otherWinController是NSWindowController的一個子類,我現在用的改變發生在更新我的窗口在代碼中,alloc init方法只是打開了nib並顯示了窗口。 showMessage是一種更改NSTextView以顯示參數中的任何文本的方法。

在NSLog中,文本每秒都在變化,只是數到十。然而,對於showMessage方法,文本在整整十秒內是空白的,然後只顯示數字10.任何想法?

FTR中,showMessage方法很簡單

- (void)showMessage:(NSString *)text { 
[[self message] setStringValue:text]; 
} 

不是它應該的問題,這是非常基本的。

回答

0

我認爲通過調用sleep(1)你可以阻塞主線程,它必須繪製你的改變。所以顯示不會更新。任務管理器不會中斷你的功能。在這種情況下,您不應該使用sleep。請看NSTimer班。它有一個靜態方法scheduledTimerWithTimeInterval,你應該使用它。

static UIViewController *controller = nil; 
..... 
{ 
..... 
otherWinController = [[NotificationWindowController alloc] init]; 
controller = otherWinController; 
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerTick:) userInfo:nil repeats:YES]; //set timer with one second interval 
..... 
} 

- (void) timerTick:(NSTimer*)theTimer { 
    static int i = 0; 
    [controller showMessage:[NSString stringWithFormat:@"%d", i]]; 
    NSLog(@"%d", i); 
    if (++i == 10) { 
     [theTimer invalidate]; 
     i = 0; 
    } 
} 
2

的問題是,您阻止主線程你for循環和用戶界面更新發生在主線程。包含for循環的方法執行完畢後,主線程運行循環將只會旋轉(因此用戶界面更新將發生)。

如果您想每秒更新一次該文本字段,則應使用計時器。例如,考慮otherWinController是一個實例變量,在你的類聲明counter財產:

otherWinController = [[NotificationWindowController alloc] init]; 
self.counter = 0; 
[otherWinController showMessage:[NSString stringWithFormat:@"%d", self.counter]]; 

[NSTimer scheduledTimerWithTimeInterval:1.0 
           target:self 
           selector:@selector(updateCounter:) 
           userInfo:nil 
           repeats:YES]; 

在同一個類中,實現的是被稱爲每當時間已被解僱的方法:

- (void)updateCounter:(NSTimer *)timer { 
    self.counter = self.counter + 1; 
    [otherWinController showMessage:[NSString stringWithFormat:@"%d", self.counter]]; 

    if (self.counter == 9) { 
     [timer invalidate]; 
     // if you want to reset the counter, 
     // self.counter = 0; 
    } 
} 
1

視圖不會更新until the end of the run loop;您的for循環不會讓運行循環繼續,因此您所做的所有視圖更新都是在for循環退出後完成的。

您應該使用NSTimerperformSelector:withObject:afterDelay:以循環方式更改顯示。

[NSTimer scheduledTimerWithTimeInterval:1 
           target:self 
           selector:@selector(changeTextFieldsString:) 
           userInfo:nil 
           repeats:YES]; 

然後你的計時器的動作會改變看法的形象:

- (void)changeTextFieldsString:(NSTimer *)tim { 
    // currStringIdx is an ivar keeping track of our position 
    if(currStringIdx >= maxStringIdx){ 
     [tim invalidate]; 
     return; 
    } 
    [otherWinController showMessage:[NSString stringWithFormat:@"%d", currStringIdx]] 
    currStringIdx++; 
} 

也一般不希望使用sleep除非你在後臺線程,因爲它會鎖定剩下的的UI;你的用戶將無法做任何事情,如果你睡得足夠長,你會得到旋轉的沙灘球。

6

你或許可以達到預期的效果就在您的內循環,如果你明確給出的運行循環一段時間運行:

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 0.1]]; 
+0

怪異,但它確實工作。 – 2011-04-29 09:39:29

+0

在桌面上執行此操作時很常見,在等待異步過程完成時運行(模態)UI。 – 2011-04-29 10:02:56

+0

有道理;感謝您分享提示! – 2011-04-29 18:11:29

相關問題