Làm cách nào để tôi gửi Clark_after GCD trong Swift 3, 4 và 5?


445

Trong Swift 2, tôi đã có thể sử dụng dispatch_afterđể trì hoãn một hành động bằng cách sử dụng công văn trung tâm lớn:

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

Nhưng điều này dường như không còn được biên dịch kể từ Swift 3. Cách ưa thích để viết điều này trong Swift hiện đại là gì?


6
Thông tin thêm về quá trình di chuyển có thể được tìm thấy ở đây: https://swift.org/migration-guide/ Phần "Công văn" có liên quan đến câu hỏi này
tonik12

câu hỏi của bạn nên được UInt64?
Mật ong

Câu trả lời:


1125

Cú pháp đơn giản là:

// to run something in 0.1 seconds

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

Lưu ý, cú pháp trên secondsnhư thêm vào Doubledường như là một nguồn gây nhầm lẫn (đặc biệt vì chúng ta đã quen với việc thêm nsec). DoubleCú pháp "thêm giây là " hoạt động vì deadlinelà một DispatchTimevà, đằng sau hậu trường, có một +toán tử sẽ mất một Doublevà thêm nhiều giây đó vào DispatchTime:

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

Nhưng, nếu bạn thực sự muốn thêm một số nguyên msec, μs hoặc nsec vào DispatchTime, bạn cũng có thể thêm a DispatchTimeIntervalvào a DispatchTime. Điều đó có nghĩa là bạn có thể làm:

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")
}

Tất cả đều hoạt động trơn tru vì phương thức quá tải riêng biệt này cho +toán tử trong DispatchTimelớp.

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

Nó được hỏi làm thế nào một người đi về việc hủy bỏ một nhiệm vụ được gửi đi. Để làm điều này, sử dụng DispatchWorkItem. Ví dụ: điều này bắt đầu một tác vụ sẽ kích hoạt trong năm giây hoặc nếu bộ điều khiển chế độ xem bị loại bỏ và giải phóng, nó deinitsẽ hủy tác vụ:

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() { ... }

}

Lưu ý việc sử dụng [weak self]danh sách chụp trong DispatchWorkItem. Điều này là cần thiết để tránh một chu kỳ tham chiếu mạnh mẽ. Cũng lưu ý rằng điều này không thực hiện hủy bỏ ưu tiên, mà chỉ dừng nhiệm vụ bắt đầu nếu nó chưa được thực hiện. Nhưng nếu nó đã bắt đầu vào thời điểm nó gặp cancel()cuộc gọi, khối sẽ hoàn thành việc thực hiện (trừ khi bạn kiểm tra thủ công isCancelledbên trong khối).


5
Cảm ơn bạn đã chỉ ra điều đó, và trên thực tế swift.org/migration-guide đề cập đến sự cần thiết phải thực hiện thay đổi đó bằng tay.
matt

1
Ồ xin lỗi. Ở đây quá muộn rồi :). Nghĩ rằng tất cả các mớ hỗn độn sẽ thực sự đi, nhưng đã không có bước nhảy vọt. IMO giải pháp "đơn giản" là giải pháp một-đúng-thật.
tobiasdm

1
@Rob làm thế nào để tôi hủy bỏ nó? Cảm ơn.
kemicofa ghost

Ok vậy làm thế nào để bạn thêm một chờ đợi năng động? Ví dụ: tôi có một số cho phép: Float = 1.0. Và .now () + .milliseconds (number) không hoạt động. Cũng không gấp đôi (số). Tôi không thể tìm ra nó.
Kjell

2
Các DispatchTimeIntervalphiên bản, như .millisecondsyêu cầu Int. Nhưng nếu chỉ thêm vài giây, tôi sẽ sử dụng Double, vd let n: Double = 1.0; queue.asyncAfter(deadline: .now() + n) { ... }.
Cướp

128

Swift 4:

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

Đối với thời gian .seconds(Int), .microseconds(Int).nanoseconds(Int)cũng có thể được sử dụng.


7
.millisecondstốt hơn gấp đôi.
DawnSong

5
Rất đẹp. Một lưu ý cho người khác: bạn cũng có thể sử dụng bất kỳ DispatchTimeIntervalgiá trị enum nào khác . case seconds(Int) case milliseconds(Int) case microseconds(Int) case nanoseconds(Int)
Rob MacEacéc

@RobMacEacéc, cảm ơn vì đề nghị hay mà tôi đã thêm nó vào câu trả lời.
Sverrisson

2
.milliseconds is better than Double. - Tôi muốn cái đó trên áo phông;).
Hoàng tử Chris

58

Nếu bạn chỉ muốn chức năng trì hoãn trong

Swift 4 & 5

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

Bạn có thể sử dụng nó như:

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

DispatchQueue.main.asyncAfter (hạn chót :) không hoạt động. Nó nói rằng nó không quá tải bất kỳ phương thức nào từ siêu lớp của nó.
Fabrizio Bartolomucci

7
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: closure)đơn giản hơn
DawnSong

16

sau khi phát hành Swift 3, cũng phải thêm @escaping

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

5

Một hương vị hơi khác nhau của câu trả lời được chấp nhận.

Swift 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

Swift 4

Bạn có thể tạo tiện ích mở rộng trên DispatchQueue và thêm độ trễ chức năng sử dụng DispatchQueuechức năng asyncAfter trong nội bộ

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

Và sử dụng

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

2
Điều này khác với câu trả lời của @ rockdaswift như thế nào?
brandonscript

như tôi đã đề cập, nó kết thúc asyncSau khi bên trong hàm PerformanceSfter có độ trễ làm tham số và có thể gọi dễ dàng hơn chỉ bằng cách thực hiệnSfter (delay: 2) {}
Suhit Patil

Các tham số đóng không được thoát theo mặc định, @escaping chỉ ra rằng một tham số đóng có thể thoát. đã thêm @ thoát tham số trong đóng để lưu sự cố tiềm ẩn.
Suhit Patil

3

gọi DispatchQueue.main.after(when: DispatchTime, execute: () -> Void)

Tôi thực sự khuyên bạn nên sử dụng các công cụ Xcode để chuyển đổi sang Swift 3 (Chỉnh sửa> Chuyển đổi> Cú pháp Swift hiện tại). Nó bắt tôi


3

Trong Swift 4.1 và Xcode 9.4.1

Câu trả lời đơn giản là ...

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

3
Không chắc làm thế nào điều này khác với câu trả lời được chấp nhận?
brandonscript

3

Swift 5 trở lên

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

1

Không có câu trả lời nào được đề cập chạy trên một chủ đề không chính, vì vậy hãy thêm 2 xu của tôi.

Trên hàng đợi chính (chủ đề chính)

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

HOẶC LÀ

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

Trên hàng đợi toàn cầu (chủ đề không chính, dựa trên QOS được chỉ định).

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

HOẶC LÀ

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

0

Điều này làm việc cho tôi trong Swift 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
Không chắc chắn làm thế nào khác với câu trả lời được chấp nhận?
brandonscript

0

Bạn có thể dùng

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

0

thử cái này

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

Không chắc chắn làm thế nào khác với câu trả lời bị ảnh hưởng?
brandonscript
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.