NSTextField aguarda até o final de um loop para atualizar

Aqui está o problema: eu tenho algum código que é assim

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

em que otherWinController é uma subclass de NSWindowController que estou usando para atualizar minha janela conforme as alterações acontecem no código, e o método aloc init simplesmente abre a ponta e mostra a janela. showMessage é um método que altera um NSTextView para exibir qualquer texto que esteja no parâmetro.

no NSLog, o texto muda a cada segundo e só conta até dez. No entanto, para o método showMessage, o texto fica em branco por dez segundos inteiros e depois exibe apenas o número 10. qualquer pensamento?

FTR, o método showMessage é simplesmente

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

Não que isso deva importar, isso é bem básico.

Você provavelmente pode obter o efeito desejado dentro do seu loop, se você explicitamente der ao loop de execução algum tempo para executar:

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

O problema é que você está bloqueando o thread principal em seu loop for e as atualizações da interface do usuário acontecem no thread principal. O loop principal de execução do encadeamento só girará (e consequentemente as atualizações da interface do usuário ocorrerão) após o método que contém o loop finalizar a execução.

Se você quiser atualizar esse campo de texto a cada segundo, você deve usar um timer. Por exemplo, considerando otherWinController é uma variável de instância, declare uma propriedade de counter em sua class e:

 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]; 

Na mesma class, implemente o método que é chamado sempre que o tempo foi acionado:

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

As visualizações não são atualizadas até o final do loop de execução ; o loop for não permite que o loop de execução continue, portanto, todas as atualizações de visualização feitas são feitas após o encerramento do loop for.

Você deve usar um NSTimer ou performSelector:withObject:afterDelay: para alterar a exibição em uma forma de loop.

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

Então a ação do seu timer mudará a imagem da vista:

 - (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++; } 

Você também geralmente não quer usar o sleep menos que esteja em um thread de segundo plano, porque ele bloqueará o restante da interface do usuário; seu usuário não poderá fazer nada e, se você dormir o suficiente, receberá a bola de praia girando.

Eu acho que chamando sleep (1) você bloqueia o thread principal, que deve desenhar suas mudanças. Portanto, a exibição não é atualizada. O gerenciador de tarefas não interromperá sua function. Você não deve usar o sono neste caso. Por favor, dê uma olhada na class NSTimer . Tem um método estático scheduledTimerWithTimeInterval , que você deve usar.

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