Swift 3, 4 및 5에서 dispatch_after GCD를 작성하는 방법


445

Swift 2에서는 dispatch_after그랜드 센트럴 디스패치를 ​​사용하여 작업을 지연시키는 데 사용할 수있었습니다 .

var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))) 
dispatch_after(dispatchTime, dispatch_get_main_queue(), { 
    // your function here 
})

그러나 이것은 더 이상 스위프트 3 이후로 컴파일되지 않는 것 같습니다. 현대 스위프트에서 이것을 작성하는 선호되는 방법은 무엇입니까?


6
마이그레이션 프로세스에 대한 자세한 내용은 여기를 참조 하십시오. https://swift.org/migration-guide/ "Dispatch"섹션은이 질문과 관련이 있습니다
tonik12

질문해야 UInt64합니까?
Honey

답변:


1125

구문은 다음과 같습니다.

// to run something in 0.1 seconds

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    // your code here
}

위의 secondsa 를 추가하는 구문은 Double혼란의 원인 인 것으로 보입니다 (nsec을 추가하는 데 익숙했기 때문에 특히 그렇습니다). 즉 "로 초를 추가 Double하기 때문에 구문 작품" deadlineDispatchTime무대 뒤에서하는 존재이며, +걸릴 것 운영자 Double와에 많은 초를 추가가 DispatchTime:

public func +(time: DispatchTime, seconds: Double) -> DispatchTime

당신이 정말로에, 밀리 μS 또는 NSEC의 정수를 추가 할 경우에, DispatchTime당신은 또한을 추가 할 수 있습니다 DispatchTimeIntervalA를 DispatchTime. 그것은 당신이 할 수 있음을 의미합니다 :

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
    os_log("500 msec seconds later")
}

DispatchQueue.main.asyncAfter(deadline: .now() + .microseconds(1_000_000)) {
    os_log("1m μs seconds later")
}

DispatchQueue.main.asyncAfter(deadline: .now() + .nanoseconds(1_500_000_000)) {
    os_log("1.5b nsec seconds later")
}

클래스 의 +운영자를 위한 별도의 오버로드 메소드로 인해 모두 원활하게 작동 합니다 DispatchTime.

public func +(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime

파견 된 작업을 취소하는 방법에 대한 질문이있었습니다. 이렇게하려면을 사용하십시오 DispatchWorkItem. 예를 들어, 5 초 내에 실행되는 작업을 시작하거나, 뷰 컨트롤러가 해제 및 할당 해제되면 deinit작업이 취소됩니다.

class ViewController: UIViewController {

    private var item: DispatchWorkItem?

    override func viewDidLoad() {
        super.viewDidLoad()

        item = DispatchWorkItem { [weak self] in
            self?.doSomething()
            self?.item = nil
        }

        DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: item!)
    }

    deinit {
        item?.cancel()
    }

    func doSomething() { ... }

}

[weak self]캡처 목록 사용에 유의하십시오 DispatchWorkItem. 이는 강력한 참조주기를 피하기 위해 필수적입니다. 또한 이것은 선점 취소를 수행하지 않고 아직 시작되지 않은 경우 작업 시작을 중지합니다. 그러나 cancel()호출 이 발생할 때까지 이미 시작된 경우 블록 isCancelled내부를 수동으로 확인하지 않는 한 블록 실행이 완료됩니다 .


5
지적 해 주셔서 감사하며 실제로 swift.org/migration-guide 는 직접 변경해야 할 필요성을 언급합니다.
matt

1
미안 너무 늦었습니다 :). 모든 혼란은 실제로 가야한다고 생각했지만 도약하지는 않았습니다. IMO "간단한"솔루션은 진정한 솔루션입니다.
tobiasdm

1
@Rob 어떻게 취소합니까? 감사.
kemicofa 유령 9

그렇다면 동적 대기를 어떻게 추가합니까? 예를 들어, let number : Float = 1.0이 있습니다. 그리고 .now () + .milliseconds (number)가 작동하지 않습니다. Double (number)도 아닙니다. 알아낼 수 없습니다.
Kjell

2
DispatchTimeInterval표현으로는, 같은 .milliseconds필요합니다 Int. 그러나 몇 초 만 추가하면 Double예를 들어을 사용 let n: Double = 1.0; queue.asyncAfter(deadline: .now() + n) { ... }합니다.
Rob

128

스위프트 4 :

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
   // Code
}

시간을 위해 .seconds(Int), .microseconds(Int)그리고 .nanoseconds(Int)또한 사용될 수있다.


7
.millisecondsDouble보다 낫습니다.
DawnSong

5
아주 좋아요 다른 사람을위한 참고 사항 : 다른 DispatchTimeInterval열거 형 값 도 사용할 수 있습니다 . case seconds(Int) case milliseconds(Int) case microseconds(Int) case nanoseconds(Int)
Rob MacEachern

@RobMacEachern, 좋은 제안으로 답변에 추가했습니다.
Sverrisson

2
.milliseconds is better than Double. -나는 티셔츠에 그것을 원한다;).
Chris Prince

58

지연 기능을 원한다면

스위프트 4 & 5

func delay(interval: TimeInterval, closure: @escaping () -> Void) {
     DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
          closure()
     }
}

다음과 같이 사용할 수 있습니다.

delay(interval: 1) { 
    print("Hi!")
}

DispatchQueue.main.asyncAfter (deadline :)가 작동하지 않습니다. 그것은 수퍼 클래스에서 어떤 메소드도 오버로드하지 않는다고 말합니다.
Fabrizio Bartolomucci

7
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: closure)더 간단합니다.
DawnSong

16

Swift 3 릴리스 후 @escaping도 추가해야합니다.

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

5

허용되는 답변의 약간 다른 맛.

스위프트 4

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1 + .milliseconds(500) + 
.microseconds(500) + .nanoseconds(1000)) {
                print("Delayed by 0.1 second + 500 milliseconds + 500 microseconds + 
                      1000 nanoseconds)")
 }

5

스위프트 4

DispatchQueue에서 확장을 작성하고 DispatchQueue내부적으로 asyncAfter 함수 를 사용하는 함수 지연을 추가 할 수 있습니다.

extension DispatchQueue {
   static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
      DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: closure)
   }
}

사용

DispatchQueue.delay(.milliseconds(10)) {
   print("task to be done")
}

2
이것은 @rockdaswift의 답변과 어떻게 다릅니 까?
brandonscript

내가 언급했듯이 매개 변수로 지연을 취하는 performAfter 함수 안에 asyncAfter를 래핑하고 performAfter (delay : 2) {}
Suhit Patil

클로저 매개 변수는 기본적으로 이스케이프가 아니며 @escaping은 클로저 매개 변수가 이스케이프 될 수 있음을 나타냅니다. 충돌 가능성을 줄이기 위해 @ escaping 매개 변수를 클로저에 추가했습니다.
Suhit Patil 2016

3

요구 DispatchQueue.main.after(when: DispatchTime, execute: () -> Void)

Xcode 도구를 사용하여 Swift 3으로 변환하는 것이 좋습니다 (편집> 변환> 현재 Swift 구문으로). 그것은 나를 위해 이것을 잡았다


3

Swift 4.1 및 Xcode 9.4.1에서

간단한 대답은 ...

//To call function after 5 seconds time
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
//Here call your function
}

3
이것이 허용되는 답변과 어떻게 다른지 확실하지 않습니까?
brandonscript

3

스위프트 5 이상

DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
   // code to execute                 
})

1

메인 스레드가 아닌 스레드에서 실행되는 언급이 없으므로 2 센트를 추가하십시오.

메인 큐 (주 스레드)

let mainQueue = DispatchQueue.main
let deadline = DispatchTime.now() + .seconds(10)
mainQueue.asyncAfter(deadline: deadline) {
    // ...
}

또는

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(10)) { 
    // ...
}

글로벌 큐 (QOS를 기반으로 논 메인 스레드는, 지정).

let backgroundQueue = DispatchQueue.global()
let deadline = DispatchTime.now() + .milliseconds(100)
backgroundQueue.asyncAfter(deadline: deadline, qos: .background) { 
    // ...
}

또는

DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + .milliseconds(100), qos: .background) {
    // ...
}

0

이것은 스위프트 3에서 나를 위해 일했습니다.

let time1 = 8.23
let time2 = 3.42

// Delay 2 seconds


DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
    print("Sum of times: \(time1 + time2)")
}

5
이것이 수락 된 답변과 어떻게 다른지 확실하지 않습니까?
brandonscript

0

당신이 사용할 수있는

DispatchQueue.main.asyncAfter(deadline: .now() + .microseconds(100)) {
        // Code
    }

0

이 시도

let when = DispatchTime.now() + 1.5
    DispatchQueue.main.asyncAfter(deadline: when) {
        //some code
    }

이것이 영향을받는 답변과 어떻게 다른지 확실하지 않습니까?
brandonscript
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.