ใน Swift วิธีการเรียกใช้เมธอดพร้อมพารามิเตอร์ในเธรดหลักของ GCD หรือไม่


192

ในแอพของฉันฉันมีฟังก์ชั่นที่ทำให้ NSRURLS เลือกและส่ง NSURLRequest โดยใช้

sesh.dataTaskWithRequest(req, completionHandler: {(data, response, error)

ในบล็อกการทำให้เสร็จสมบูรณ์สำหรับงานนี้ฉันต้องทำการคำนวณบางอย่างที่เพิ่ม UIImage ไปยังตัวเรียก viewcontroller ฉันมีสิ่งที่เรียกว่า func

func displayQRCode(receiveAddr, withAmountInBTC:amountBTC)

นั่นคือการคำนวณการเพิ่ม UIImage ถ้าฉันพยายามเรียกใช้โค้ดเพิ่มการดูภายในบล็อกเสร็จสมบูรณ์ Xcode จะมีข้อผิดพลาดแจ้งว่าฉันไม่สามารถใช้เลย์เอาต์เอ็นจิ้นในขณะที่อยู่ในกระบวนการพื้นหลัง ดังนั้นฉันพบรหัสบางส่วนใน SO ที่พยายามจัดคิววิธีในเธรดหลัก:

let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.0 * Double(NSEC_PER_MSEC)))

dispatch_after(time, dispatch_get_main_queue(), {
    let returned = UIApplication.sharedApplication().sendAction("displayQRCode:", to: self.delegate, from: self, forEvent: nil)
})

อย่างไรก็ตามฉันไม่ทราบวิธีการเพิ่มพารามิเตอร์ "receiveAddr" และ "amountBTC" ในการเรียกใช้ฟังก์ชันนี้ ฉันจะทำสิ่งนี้หรือใครบางคนสามารถแนะนำวิธีที่ดีที่สุดสำหรับการเพิ่มวิธีการโทรไปยังคิวหลักของแอปพลิเคชัน?

คำตอบ:


497

Swift เวอร์ชันใหม่ใช้DispatchQueue.main.asyncเพื่อส่งไปยังเธรดหลัก:

DispatchQueue.main.async { 
  // your code here
}

ในการจัดส่งหลังจากบนคิวหลักให้ใช้:

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

Swift รุ่นที่เก่ากว่าใช้:

dispatch_async(dispatch_get_main_queue(), {
  let delegateObj = UIApplication.sharedApplication().delegate as YourAppDelegateClass
  delegateObj.addUIImage("yourstring")
})

ในขณะที่คุณถูกต้องว่าคำแนะนำของคุณใช้งานได้ฉันคิดว่าคำตอบของฉันดีกว่าเล็กน้อยเพราะไม่ได้โทรไปที่ UIApplication.sharedApplication ซึ่งผิดปกติและอาจทำให้ผู้อ่านรหัสของฉันออกไป ขอบเขตของคำตอบของฉันถูก จำกัด กับวัตถุที่มีความสำคัญในขณะที่ของคุณนำมาในวัตถุเสริมที่ต้องการให้ฉันอ่านเอกสารเพิ่มเติมเพื่อเรียนรู้สิ่งที่ฉันทำ และฉันได้แก้ไขคำถามเดิมของฉันเพื่อให้มีการเรียกใช้ฟังก์ชันที่ถูกต้อง ฉันคิดว่า displayQRC นั้นไม่เฉพาะเจาะจง แต่ด้วยความคิดเห็นของเราในตอนนี้ ขอบคุณสำหรับการชี้ให้เห็นว่า
อัลเมล

84

รุ่น Swift 3+ และ Swift 4:

DispatchQueue.main.async {
    print("Hello")
}

Swift 3 และ Xcode 9.2:

dispatch_async_on_main_queue {
    print("Hello")
}

15

สวิฟท์ 2

เมื่อใช้ Trailing Closures สิ่งนี้จะกลายเป็น:

dispatch_async(dispatch_get_main_queue()) {
    self.tableView.reloadData()
}

Trailing Closures คือ Swift syntactic sugar ที่ให้คำจำกัดความการปิดอยู่นอกขอบเขตพารามิเตอร์ฟังก์ชั่น สำหรับข้อมูลเพิ่มเติมให้ดูที่Trailing Closuresในคู่มือการเขียนโปรแกรมภาษา Swift 2.2

ในกรณี dispatch_async API คือfunc dispatch_async(queue: dispatch_queue_t, _ block: dispatch_block_t)ตั้งแต่dispatch_block_tเป็นชนิดนามแฝงสำหรับ() -> Void- ปิดที่ได้รับ 0 dispatch_asyncพารามิเตอร์และไม่ได้มีค่าตอบแทนและบล็อกเป็นพารามิเตอร์สุดท้ายของฟังก์ชั่นที่เราสามารถกำหนดปิดในขอบเขตด้านนอกของ


1
นั่นคือ 3 บรรทัดที่ฉันกำลังมองหา ... ตอนนี้คุณสามารถหยุดอ่านใจของฉันได้
Laszlo


7

นี่คือไวยากรณ์สไตล์ nicer (IMO) Swifty / Cocoa เพื่อให้ได้ผลลัพธ์เช่นเดียวกับคำตอบอื่น ๆ :

NSOperationQueue.mainQueue().addOperationWithBlock({
    // Your code here
})

หรือคุณสามารถคว้าไลบรารี่ Async Swiftยอดนิยมสำหรับรหัสที่น้อยลงและฟังก์ชั่นเพิ่มเติม:

Async.main {
    // Your code here
}

วิธีเปลี่ยนชื่อเป็นOperationQueue.main.addOperation({ }
Frostmourne

3

วิธีที่เหมาะสมในการทำเช่นนี้คือใช้ dispatch_async ใน main_queue อย่างที่ฉันทำในรหัสต่อไปนี้

dispatch_async(dispatch_get_main_queue(), {
    (self.delegate as TBGQRCodeViewController).displayQRCode(receiveAddr, withAmountInBTC:amountBTC)
})

2

นี่เป็นฟังก์ชั่นระดับโลกเล็ก ๆ ที่ดีที่คุณสามารถเพิ่มสำหรับไวยากรณ์ของ nicer:

func dispatch_on_main(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

และการใช้งาน

dispatch_on_main {
    // Do some UI stuff
}

2
//Perform some task and update UI immediately.
DispatchQueue.global(qos: .userInitiated).async {  
    // Call your function here
    DispatchQueue.main.async {  
        // Update UI
        self.tableView.reloadData()  
    }
}

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

//If you want to do changes in UI use this
DispatchQueue.main.async(execute: {
    //Update UI
    self.tableView.reloadData()
})

2

อย่าลืมทำให้ตัวเองอ่อนแอถ้าคุณใช้ตัวเองอยู่ในการปิด

dispatch_async(dispatch_get_main_queue(),{ [weak self] () -> () in
    if let strongSelf = self {
        self?.doSomething()
    }
})

1
คุณช่วยอธิบายได้ไหมว่าทำไมเราควรทำสิ่งนี้
Jackspicer

เป็นเพราะมันสามารถสร้างรอบหน่วยความจำ - เช่นฉันมีการอ้างอิงที่แข็งแกร่งกับบางสิ่งบางอย่างและมีการอ้างอิงที่แข็งแกร่งกับฉัน ความหมายของเราไม่สามารถทิ้งความทรงจำกอง
jackofallcode
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.