Cách lập trình độ trễ trong Swift 3


329

Trong các phiên bản trước của Swift, người ta có thể tạo độ trễ với mã sau:

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
}

Nhưng bây giờ, trong Swift 3, Xcode tự động thay đổi 6 thứ khác nhau nhưng sau đó xuất hiện lỗi sau: "Không thể chuyển đổi DispatchTime.nowthành giá trị mong đợi dispatch_time_taka UInt64".

Làm cách nào để tạo độ trễ trước khi chạy chuỗi mã trong Swift 3?

Câu trả lời:


964

Sau rất nhiều nghiên cứu, cuối cùng tôi đã tìm ra cái này.

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

Điều này tạo ra hiệu ứng "chờ" mong muốn trong Swift 3 và Swift 4.

Lấy cảm hứng từ một phần của câu trả lời này .


7
Đóng góp hữu ích, cảm ơn! Cập nhật cho Swift 3 gần đây nhất:DispatchQueue.main.asyncAfter(deadline: when)
Rogare

77
Bạn có thể làm cho mã của mình nhanh hơn một chút bằng cách thay thế "+ 2" bằng "+ .seconds (2)". Hoặc, để đạt được kết quả cuối cùng, bạn có thể bỏ dòng đầu tiên và thay thế "thời hạn: khi" bằng "thời hạn: .now () + .seconds (2)".
RenniePet

2
@ OctavioAntonioCedeño Rất vui được giúp đỡ. Điều này thực sự làm tôi khó chịu trong một thời gian: D
Owlswipe

5
Vẫn hoạt động 3/12/2017. Cảm ơn bạn rất nhiều vì điều này :)
John Leonardo

3
Nghĩa đen là bài đăng của tôi được truy cập nhiều nhất trên SO. Tìm bài đăng này dễ hơn là thực sự nhớ nó hoặc tìm nó ở nơi khác trong mã của tôi;)
barrylachapelle

154

Tôi thích ký hiệu một dòng cho GCD, nó thanh lịch hơn:

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

Ngoài ra, trong iOS 10, chúng tôi có các phương thức Timer mới, ví dụ: trình khởi tạo khối:

(vì vậy hành động chậm trễ có thể bị hủy bỏ)

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

Btw, hãy ghi nhớ: theo mặc định, bộ đếm thời gian được thêm vào chế độ vòng lặp chạy mặc định. Điều đó có nghĩa là bộ hẹn giờ có thể bị đóng băng khi người dùng tương tác với giao diện người dùng của ứng dụng của bạn (ví dụ: khi cuộn UIScrollView) Bạn có thể giải quyết vấn đề này bằng cách thêm bộ hẹn giờ vào chế độ vòng lặp chạy cụ thể:

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

Tại bài viết blog này, bạn có thể tìm thêm chi tiết.


4
Nắm bắt tốt! Tôi chưa thấy điều này.
julien_c

8
cộng với một để so sánh Timer và từ chối trách nhiệm về runloop chính!
Martin

2
Bắt tốt đẹp! Đây là kỹ thuật.
Onur Şahindur

56

Hãy thử chức năng sau được triển khai trong Swift 3.0 trở lên

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

Sử dụng

delayWithSeconds(1) {
   //Do something
}

5
Bạn về cơ bản chỉ cần sao chép câu trả lời này nhưng có, điều này là tốt, cảm ơn.
Owlswipe

2
Làm thế nào để hủy bỏ điều này?
Sourav Chandra

24

Hãy thử mã dưới đây để trì hoãn

//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
Màn hình theo cách thứ nhất có lỗi "Sử dụng số nhận dạng chưa được giải quyết 'độ trễ'"
Jerry Chong

5
Lập trình viên này đang làm việc với một phương thức trợ giúp trong cơ sở mã của mình và có một thời gian dài. Vì vậy, độ trễ là mã mà anh ấy đã sử dụng trong một thời gian mà không biết nó không nằm ngoài SDK của Apple.
Nick Perkins

4

Một cách là sử dụng DispatchQueue.main.asyncAfternhư rất nhiều người đã trả lời.

Một cách khác là sử dụng perform(_:with:afterDelay:). Thêm chi tiết tại đây

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

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

1

// Chạy chức năng sau x giây

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

//Sử dụng:-

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