Como posso atrasar uma chamada de método por 1 segundo?


164

Existe uma maneira fácil de atrasar uma chamada de método por 1 segundo?

Eu tenho um UIImageViewque reage a um evento de toque. Quando o toque é detectado, algumas animações acontecem no aplicativo. Depois de um segundo, quero chamar outro método. Nesse caso, não posso usar o animationDidStopseletor.


Certamente, existem várias maneiras de fazer isso, uma delas pode ser simplesmente usar sleep () para suspender o programa / thread por vários milissegundos, no entanto , acho que você pode nos dizer exatamente o que está tentando realizar fazendo isso? Quero dizer, qual é o seu problema real? A idéia de adiar uma chamada de método parece ser uma 'solução', que não parece boa demais para ser honesta. Então, conte-nos mais sobre o cenário que você tem em mente.
nenhum

Respostas:


254
performSelector:withObject:afterDelay:

Referência do Documento



Existe alguma maneira de algo com o valor de retorno do método que é chamado? Ou preciso configurá-lo para modificar o parâmetro se quiser obter algumas informações dele?
Gordon Gustafson

se alguém estiver interessado em como cancelar uma chamada agendada: [NSObject cancelPreviousPerformRequestsWithTarget: seletor yourTarget: aSelector objeto: anArgument];
vir us 27/08

192

Você também pode usar um bloco

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    [object method]; 
});

Na maioria das vezes, você desejará usar dispatch_get_main_queue, embora, se não houver interface do usuário no método, você possa usar uma fila global .

Editar:

Versão Swift 3:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    object.method()
}

Da mesma forma, DispatchQueue.global().asyncAfter(...também pode ser uma boa opção.


Encontrado esta solução a ser mais fácil do que quando a mistura de performSelector C linear e ObjC
Paul Slocum

1
Infelizmente dispatch_get_current_queue está obsoleto desde o iOS6
chrisben

3
Atualizado para usar dispatch_get_main_queue em vez de dispatch_get_current_queue
mcfedr

2
Xcode agora auto completar isso, basta começar a digitar dispatch_aftere pressione enter
mcfedr

1
Especialmente agora que o Xcode preenche isso automaticamente ao digitar dispatch_after, essa é realmente uma maneira super direta de fazer isso, além de você poder passar propriedades para o método que você está chamando, o que é ótimo.
Erik van der Neut

128

A melhor maneira de fazer é:

[self performSelector:@selector(YourFunctionName) 
           withObject:(can be Self or Object from other Classes) 
           afterDelay:(Time Of Delay)];

você também pode passar nulo como com o parâmetro Object.

exemplo:

[self performSelector:@selector(subscribe) withObject:self afterDelay:3.0 ];

3
Por que você passaria a si mesmo?
Eric

2
E por que você passaria uma variável para um método que recebe zero argumentos?
Hellozimi #

23

Já existem muitas respostas e todas estão corretas. No caso de você querer usar, dispatch_afterprocure o snippet que está incluído Code Snippet Libraryna parte inferior direita (onde é possível selecionar os UIelementos).

insira a descrição da imagem aqui

Então, você só precisa chamar esse snippet escrevendo dispatch no código:

insira a descrição da imagem aqui


16

Você pode usar o seletor de execução para depois que o método de atraso de 0,1 s for chamado para o código a seguir para fazer isso.

[self performSelector:@selector(InsertView)  withObject:nil afterDelay:0.1]; 

9

Você também pode:

[UIView animateWithDuration:1.0
                 animations:^{ self.view.alpha = 1.1; /* Some fake chages */ }
                 completion:^(BOOL finished)
{
    NSLog(@"A second lapsed.");
}];

Nesse caso, você precisa falsificar algumas alterações em algumas visualizações para obter o trabalho de animação. É realmente hacky, mas eu amo o material baseado em bloco. Ou encerre a resposta @mcfedr abaixo.


waitFor(1.0, ^
{
    NSLog(@"A second lapsed");
});

typedef void (^WaitCompletionBlock)();
void waitFor(NSTimeInterval duration, WaitCompletionBlock completion)
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC),
                   dispatch_get_main_queue(), ^
    { completion(); });
}

Não tenho certeza, mas acho que a primeira opção que você sugere pode ter efeitos colaterais que os usuários devem estar cientes, por exemplo, bloquear a interação do usuário em partes da interface do usuário. Meu instinto é que isso também causaria uma CPU desnecessária ou outra drenagem de recursos, mas não verifiquei.
Bjorn Roche

8

Você consegue fazer isso

[self performSelector:@selector(MethodToExecute) withObject:nil afterDelay:1.0 ];

4

Swift 2.x

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
 dispatch_after(delayTime, dispatch_get_main_queue()) {
 print("do some work")
}

Swift 3.x - e - Swift 4

DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
    print("do some work")
}

ou passar um escaping closure

func delay(seconds: Double, completion: @escaping()-> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + seconds, execute: completion)
}

1

Existe uma solução Swift 3 na solução verificada:

self.perform(#selector(self.targetMethod), with: self, afterDelay: 1.0)

E existe o método

@objc fileprivate func targetMethod(){

}


-34

NOTA: isso pausará todo o thread, não apenas o método.
Fazer uma chamada para suspensão / espera / parada por 1000 ms antes de chamar seu método?

Sleep(1000); // does nothing the next 1000 mSek

Methodcall(params); // now do the real thing

Editar: A resposta acima se aplica à pergunta geral "Como posso atrasar uma chamada de método por 1 segundo?", Que foi a pergunta feita no momento da resposta (na verdade, a resposta foi dada dentro de 7 minutos da pergunta original: - )). Nenhuma informação foi dada sobre o idioma naquele momento; portanto, pare de reclamar sobre a maneira correta de usar o sono no XCode e na falta de aulas ...


Somente no segmento atual, outros segmentos continuarão em execução.
803 Marc Charbonneau

4
Nossa. Eu entendo por que isso foi rejeitado algumas vezes, mas quem diabos viu isso em -27 e decidiu que precisava de outro? -3 ou algo não esclarece o ponto. Por que não apenas editar a resposta para dizer "isso fará uma pausa em todo o tópico" ou algo assim, em vez de diminuir o voto das pessoas?
Albert Renshaw

E daí se você quiser pausar todo o tópico? Parece uma opção válida se for fornecida com um aviso decente.
Departamento B

@AlbertRenshaw Eu concordo totalmente com você. Estou aqui e seus 35 baixos e dei-lhe o meu. Vejo mais como atacar tanto os usuários de baixa reputação. Ninguém fará nenhuma edição ou especificará nada. Eu vi uma resposta hoje que realmente se afogou. O único erro que essa pessoa cometeu é que ela respondeu sob uma pergunta rápida com linguagem c objetiva. Se for um grande erro, quero mostrar tantas respostas rápidas nas perguntas objetivas c.
soorej babu 02/01
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.