NSTextField ожидает до конца цикла для обновления - PullRequest
2 голосов
/ 29 апреля 2011

Вот проблема: у меня есть код, который выглядит так

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 просто открывает перо и показывает окно. showMessage - это метод, который изменяет NSTextView для отображения любого текста в параметре.

в NSLog, текст меняется каждую секунду и просто считается до десяти. Однако для метода showMessage текст остается пустым в течение полных десяти секунд, а затем просто отображается число 10. любые мысли ??

FTR, метод showMessage просто

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

не то чтобы это должно было иметь значение, это довольно просто.

Ответы [ 4 ]

6 голосов
/ 29 апреля 2011

Вероятно, вы можете достичь желаемого эффекта прямо внутри цикла, если явно дадите циклу выполнения некоторое время для запуска:

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 0.1]];
2 голосов
/ 29 апреля 2011

Проблема в том, что вы блокируете основной поток в цикле 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 голос
/ 29 апреля 2011

Представления не обновляются до конца цикла выполнения ; ваш for цикл не позволяет циклу выполнения продолжаться, поэтому все обновления представлений, которые вы делаете, просто выполняются после выхода из цикла for.

Вы должны использовать NSTimer или performSelector: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, если вы не находитесь в фоновом потоке, потому что он заблокирует остальную часть пользовательского интерфейса; ваш пользователь не сможет ничего сделать, и если вы будете спать достаточно долго, вы получите вращающийся пляжный мяч.

0 голосов
/ 29 апреля 2011

Я думаю, что, вызывая sleep (1) , вы блокируете основной поток, который должен отрисовывать ваши изменения.Так что дисплей не обновляется.Диспетчер задач не будет прерывать вашу функцию.Вы не должны использовать sleep в этом случае.Пожалуйста, взгляните на NSTimer класс.У него есть статический метод scheduleTimerWithTimeInterval , который вы должны использовать.

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;
    }
}
...