Como programar um atraso no Swift 3


330

Nas versões anteriores do Swift, era possível criar um atraso com o seguinte código:

let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 4 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
    //put your code which should be executed with a delay here
}

Mas agora, no Swift 3, o Xcode altera automaticamente 6 coisas diferentes, mas o seguinte erro aparece: "Não é possível converter DispatchTime.nowpara o valor esperado dispatch_time_taka UInt64".

Como se pode criar um atraso antes de executar uma sequência de código no Swift 3?

Respostas:


966

Depois de muita pesquisa, eu finalmente descobri isso.

DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { // Change `2.0` to the desired number of seconds.
   // Code you want to be delayed
}

Isso cria o efeito de "espera" desejado no Swift 3 e Swift 4.

Inspirado por uma parte desta resposta .


7
Contribuição útil, obrigado! Atualizando para o Swift 3 mais recente:DispatchQueue.main.asyncAfter(deadline: when)
Rogare 07/09/16

77
Você pode tornar seu código um pouco mais rápido substituindo "+ 2" por "+ .seconds (2)". Ou, para obter o máximo de rapidez, você pode soltar a primeira linha e substituir "deadline: when" por "deadline: .now () + .seconds (2)".
precisa saber é o seguinte

2
@ OctavioAntonioCedeño Feliz em ajudar. Isso realmente me
incomodou

5
Ainda trabalhando em 12/03/2017. Muito obrigado por este :)
John Leonardo

3
Literalmente, o meu post mais visitado no SO. É mais fácil encontrar esse post do que realmente lembre-lo ou encontrá-lo em outro lugar no meu código;)
barrylachapelle

154

Eu gosto da notação de uma linha para o GCD, é mais elegante:

    DispatchQueue.main.asyncAfter(deadline: .now() + 42.0) {
        // do stuff 42 seconds later
    }

Além disso, no iOS 10, temos novos métodos de Timer, por exemplo, inicializador de bloco:

(a ação atrasada pode ser cancelada)

    let timer = Timer.scheduledTimer(withTimeInterval: 42.0, repeats: false) { (timer) in
        // do stuff 42 seconds later
    }

Lembre-se: por padrão, o timer é adicionado ao modo padrão de loop de execução. Isso significa que o cronômetro pode ser congelado quando o usuário está interagindo com a interface do usuário do seu aplicativo (por exemplo, ao rolar um UIScrollView) Você pode resolver esse problema adicionando o cronômetro ao modo de loop de execução específico:

RunLoop.current.add(timer, forMode: .common)

Nesta postagem do blog, você pode encontrar mais detalhes.


4
Boa pegada! Eu ainda não tinha visto isso.
Jul16

8
mais um para a comparação do temporizador e o aviso sobre o runloop principal!
Martin

2
Boa pegada! Isso é engenharia.
Onur indahindur 15/10

56

Experimente a seguinte função implementada no Swift 3.0 e superior

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

Uso

delayWithSeconds(1) {
   //Do something
}

5
Você basicamente copiou esta resposta, mas sim, isso é bom, obrigado.
owlswipe

2
Como cancelar isso?
Sourav Chandra

24

Tente o código abaixo para atraso

//MARK: First Way

func delayForWork() {
    delay(3.0) {
        print("delay for 3.0 second")
    }
}

delayForWork()

// MARK: Second Way

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    // your code here delayed by 0.5 seconds
}

1
Os monitores da primeira maneira apresentam o erro "Uso do identificador não resolvido 'atraso'"
Jerry Chong

5
Este programador está trabalhando com um método auxiliar em sua base de código e trabalha há muito tempo. Portanto, o atraso foi o código que ele usou por um tempo sem saber que não faz parte do SDK da Apple.
Nick Perkins

4

Uma maneira é usar DispatchQueue.main.asyncAftercomo muitas pessoas responderam.

Outra maneira é usar perform(_:with:afterDelay:). Mais detalhes aqui

perform(#selector(delayedFunc), with: nil, afterDelay: 3)

@IBAction func delayedFunc() {
    // implement code
}

1

// Executa a função após x segundos

public static func runThisAfterDelay(seconds: Double, after: @escaping () -> Void) {
    runThisAfterDelay(seconds: seconds, queue: DispatchQueue.main, after: after)
}

public static func runThisAfterDelay(seconds: Double, queue: DispatchQueue, after: @escaping () -> Void) {
    let time = DispatchTime.now() + Double(Int64(seconds * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
    queue.asyncAfter(deadline: time, execute: after)
}

//Usar:-

runThisAfterDelay(seconds: x){
  //write your code here
}
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.