วิธีตั้งโปรแกรมการหน่วงเวลาใน Swift 3


330

ในรุ่นก่อนหน้าของ Swift หนึ่งสามารถสร้างความล่าช้าด้วยรหัสต่อไปนี้:

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
}

แต่ตอนนี้ใน Swift 3 Xcode จะเปลี่ยนสิ่งต่าง ๆ 6 อย่างโดยอัตโนมัติ แต่แล้วข้อผิดพลาดต่อไปนี้จะปรากฏขึ้น: "ไม่สามารถแปลงDispatchTime.nowเป็นค่าที่คาดหวังdispatch_time_t aka UInt64."

เราจะสร้างความล่าช้าก่อนที่จะรันลำดับของรหัสใน Swift 3 ได้อย่างไร

คำตอบ:


966

หลังจากการวิจัยจำนวนมากในที่สุดฉันก็พบสิ่งนี้ออกมา

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

สิ่งนี้จะสร้างเอฟเฟกต์ "รอ" ที่ต้องการใน Swift 3 และ Swift 4

แรงบันดาลใจจากส่วนหนึ่งของคำตอบนี้


7
ผลงานที่เป็นประโยชน์ขอบคุณ! อัปเดตสำหรับ Swift 3 ล่าสุด:DispatchQueue.main.asyncAfter(deadline: when)
Rogare

77
คุณสามารถทำให้โค้ดของคุณรวดเร็วยิ่งขึ้นอีกนิดโดยแทนที่ "+ 2" ด้วย "+ .seconds (2)" หรือสำหรับสุดยอด swiftyness คุณสามารถวางบรรทัดแรกและแทนที่ "กำหนดเวลา: เมื่อ" ด้วย "กำหนดเวลา: .now () + .seconds (2)"
RenniePet

2
@ OctavioAntonioCedeñoยินดีช่วยเหลือ สิ่งนี้ทำให้ฉัน
รำคาญ

5
ยังคงทำงาน 3/12/2017 ขอบคุณมากสำหรับสิ่งนี้ :)
John Leonardo

3
โพสต์ที่ฉันเข้าชมบ่อยที่สุดบน SO การค้นหาโพสต์นี้ง่ายกว่าจำจริง ๆ หรือค้นหาที่อื่นในรหัสของฉัน;)
24922

154

ฉันชอบสัญกรณ์หนึ่งบรรทัดสำหรับ GCD มันสวยกว่า:

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

นอกจากนี้ใน iOS 10 เรามีวิธีตั้งเวลาใหม่เช่น block initializer:

(การดำเนินการล่าช้าอาจถูกยกเลิก)

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

Btw โปรดทราบว่า: โดยค่าเริ่มต้นตัวจับเวลาจะถูกเพิ่มในโหมดวนรอบเริ่มต้น หมายถึงตัวจับเวลาอาจหยุดการทำงานเมื่อผู้ใช้โต้ตอบกับ UI ของแอปของคุณ (ตัวอย่างเช่นเมื่อเลื่อน UIScrollView) คุณสามารถแก้ไขปัญหานี้ได้โดยการเพิ่มตัวจับเวลาไปที่โหมดลูปเรียกใช้เฉพาะ:

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

ที่โพสต์บล็อกนี้คุณสามารถค้นหารายละเอียดเพิ่มเติม


4
จับดี! ฉันยังไม่เห็นสิ่งนี้
julien_c

8
บวกหนึ่งสำหรับการเปรียบเทียบตัวจับเวลาและข้อจำกัดความรับผิดชอบเกี่ยวกับ runloop หลัก!
Martin

2
รับได้สวย! นี่คือวิศวกรรม
Onur Şahindur

56

ลองใช้ฟังก์ชั่นต่อไปนี้ในSwift 3.0 ขึ้นไป

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

การใช้

delayWithSeconds(1) {
   //Do something
}

5
คุณเพียงแค่คัดลอกคำตอบนี้โดยทั่วไปแต่ใช่ดีมากขอบคุณ
owlswipe

2
จะยกเลิกได้อย่างไร?
Sourav Chandra

24

ลองใช้รหัสด้านล่างเพื่อดูความล่าช้า

//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
วิธีแรกที่แสดงมีข้อผิดพลาด "การใช้ตัวระบุที่ไม่ได้รับการแก้ไข 'ล่าช้า'"
Jerry Chong

5
โปรแกรมเมอร์นี้ทำงานร่วมกับวิธีการช่วยเหลือในฐานรหัสของเขาและใช้เวลานาน ดังนั้นความล่าช้าเป็นรหัสที่เขาใช้มาระยะหนึ่งแล้วไม่รู้ว่ามันไม่ได้อยู่นอกเหนือจาก SDK ของ Apple
Nick Perkins


1

// เรียกใช้ฟังก์ชันหลังจาก x วินาที

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

//ใช้:-

runThisAfterDelay(seconds: x){
  //write your code here
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.