Estou tendo um comportamento estranho com presentViewController:animated:completion
. O que estou fazendo é essencialmente um jogo de adivinhação.
Eu tenho um UIViewController
(frequencyViewController) contendo um UITableView
(frequencyTableView). Quando o usuário toca na linha em questionTableView que contém a resposta correta, uma visualização (correctViewController) deve ser instanciada e sua visualização deve deslizar para cima da parte inferior da tela, como uma visualização modal. Isso informa ao usuário que ele tem uma resposta correta e redefine o frequencyViewController atrás dele, pronto para a próxima pergunta. correctViewController é dispensado ao pressionar um botão para revelar a próxima pergunta.
Isso tudo funciona corretamente todas as vezes, e a visualização do corretoViewController aparece instantaneamente, desde que presentViewController:animated:completion
tenha animated:NO
.
Se eu definir animated:YES
, correctViewController é inicializado e faz chamadas para viewDidLoad
. No entanto viewWillAppear
, viewDidAppear
e o bloco de conclusão de presentViewController:animated:completion
não são chamados. O aplicativo fica lá, ainda mostrando o frequencyViewController, até que eu faça um segundo toque. Agora, viewWillAppear, viewDidAppear e o bloco de conclusão são chamados.
Investiguei um pouco mais, e não é apenas outro toque que fará com que continue. Parece que se eu inclinar ou sacudir meu iPhone, isso também pode fazer com que ele acione o viewWillLoad etc. É como se ele estivesse esperando por qualquer outra entrada do usuário antes de prosseguir. Isso acontece em um iPhone real e no simulador, o que eu provei enviando o comando shake para o simulador.
Estou realmente sem saber o que fazer sobre isso ... Eu realmente aprecio qualquer ajuda que alguém possa fornecer.
obrigado
Aqui está meu código. É bem simples ...
Este é o código em questionViewController que atua como delegado para questionTableView
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row != [self.frequencyModel currentFrequencyIndex])
{
// If guess was wrong, then mark the selection as incorrect
NSLog(@"Incorrect Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
UITableViewCell *cell = [self.frequencyTableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor colorWithRed:240/255.0f green:110/255.0f blue:103/255.0f alpha:1.0f]];
}
else
{
// If guess was correct, show correct view
NSLog(@"Correct Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
self.correctViewController = [[HFBCorrectViewController alloc] init];
self.correctViewController.delegate = self;
[self presentViewController:self.correctViewController animated:YES completion:^(void){
NSLog(@"Completed Presenting correctViewController");
[self setUpViewForNextQuestion];
}];
}
}
Este é todo o correctViewController
@implementation HFBCorrectViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
NSLog(@"[HFBCorrectViewController initWithNibName:bundle:]");
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(@"[HFBCorrectViewController viewDidLoad]");
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"[HFBCorrectViewController viewDidAppear]");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)close:(id)sender
{
NSLog(@"[HFBCorrectViewController close:sender:]");
[self.delegate didDismissCorrectViewController];
}
@end
Editar:
Eu encontrei esta pergunta antes: UITableView e presentViewController levam 2 cliques para exibir
E se eu mudar meu didSelectRow
código para isso, ele funciona muito bem com animação ... Mas é confuso e não faz sentido por que não funciona em primeiro lugar. Então eu não considero isso uma resposta ...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row != [self.frequencyModel currentFrequencyIndex])
{
// If guess was wrong, then mark the selection as incorrect
NSLog(@"Incorrect Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
UITableViewCell *cell = [self.frequencyTableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor colorWithRed:240/255.0f green:110/255.0f blue:103/255.0f alpha:1.0f]];
// [cell setAccessoryType:(UITableViewCellAccessoryType)]
}
else
{
// If guess was correct, show correct view
NSLog(@"Correct Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
////////////////////////////
// BELOW HERE ARE THE CHANGES
[self performSelector:@selector(showCorrectViewController:) withObject:nil afterDelay:0];
}
}
-(void)showCorrectViewController:(id)sender
{
self.correctViewController = [[HFBCorrectViewController alloc] init];
self.correctViewController.delegate = self;
self.correctViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:self.correctViewController animated:YES completion:^(void){
NSLog(@"Completed Presenting correctViewController");
[self setUpViewForNextQuestion];
}];
}
fonte
presentViewController:
deve ser acionada começa com um grande atraso. Este parece ser um bug no iOS 7 e também é discutido no Apple Dev Forums.Respostas:
Eu encontrei o mesmo problema hoje. Eu cavei no tópico e parece que está relacionado ao runloop principal estar dormindo.
Na verdade, é um bug muito sutil, porque se você tiver o menor feedback de animação, temporizadores, etc. em seu código, esse problema não aparecerá porque o loop de execução será mantido vivo por essas fontes. Eu encontrei o problema usando um
UITableViewCell
que tinha seuselectionStyle
definido comoUITableViewCellSelectionStyleNone
, de modo que nenhuma animação de seleção acionou o loop de execução depois que o manipulador de seleção de linha foi executado.Para consertar (até que a Apple faça algo), você pode acionar o loop de execução principal de vários meios:
A solução menos intrusiva é chamar
CFRunLoopWakeUp
:Ou você pode enfileirar um bloco vazio na fila principal:
É engraçado, mas se você sacudir o dispositivo, ele também acionará o loop principal (ele deve processar os eventos de movimento). O mesmo acontece com os toques, mas isso está incluído na pergunta original :) Além disso, se o sistema atualizar a barra de status (por exemplo, as atualizações do relógio, a intensidade do sinal WiFi muda, etc.), isso também ativará o loop principal e apresentará a visualização controlador.
Para qualquer pessoa interessada, escrevi um projeto de demonstração mínima do problema para verificar a hipótese de loop de execução: https://github.com/tzahola/present-bug
Também relatei o bug à Apple.
fonte
Confira: https://devforums.apple.com/thread/201431 Se você não quiser ler tudo - a solução para algumas pessoas (inclusive eu) foi fazer a
presentViewController
chamada explicitamente no thread principal:Swift 4.2:
Objective-C:
Provavelmente iOS7 está bagunçando os fios
didSelectRowAtIndexPath
.fonte
Eu o ignorei no Swift 3.0 usando o seguinte código:
fonte
present
para um retorno de chamada de encerramento.Chamar
[viewController view]
o controlador de visualização que está sendo apresentado funcionou para mim.fonte
Eu estaria curioso para ver o que
[self setUpViewForNextQuestion];
faz.Você pode tentar ligar
[self.correctViewController.view setNeedsDisplay];
no final do seu bloco de conclusão empresentViewController
.fonte
Correct Guess: 1 kHz 18:04:57.173 Frequency[641:60b] [HFBCorrectViewController initWithNibName:bundle:] 18:04:57.177 Frequency[641:60b] [HFBCorrectViewController viewDidLoad]
Agora nada acontece até: Tap 218:05:00.515 Frequency[641:60b] [HFBCorrectViewController viewDidAppear] 18:05:00.516 Frequency[641:60b] Completed Presenting correctViewController 18:05:00.517 Frequency[641:60b] [HFBFrequencyViewController setUpViewForNextQuestion]
Eu escrevi extensão (categoria) com método swizzling para UIViewController que resolve o problema. Agradecimentos a AX e NSHipster pelas dicas de implementação ( swift / objetiva-c ).
Rápido
Objective-C
fonte
Verifique se a sua célula no storyboard tem Seleção = nenhum
Se sim, mude para azul ou cinza e deve funcionar
fonte
XCode Vesion: 9.4.1, Swift 4.1
No meu caso isso acontece, quando toco no celular e passo para a outra visualização. Eu depuro mais profundamente e parece que isso acontece internamente
viewDidAppear
porque contém o seguinte códigoem seguida, adicionei o segmento de código acima
prepare(for segue: UIStoryboardSegue, sender: Any?)
e funcionou perfeitamente.Na minha experiência, minha solução é, se quisermos fazer novas alterações (por exemplo, recarregar a tabela, desmarcar a célula selecionada etc.) para o tableview quando voltar da segunda visualização, então use delegate em vez de
viewDidAppear
usar otableView.deselectRow
código acima segmento antes de mover o segundo controlador de vistafonte