कार्य समाप्त होने तक प्रतीक्षा की जा रही है


99

DispatchQueue खत्म होने तक मैं अपना कोड कैसे प्रतीक्षा कर सकता हूं? क्या इसे किसी कंप्लीशनहैंडलर या किसी चीज़ की ज़रूरत है?

func myFunction() {
    var a: Int?

    DispatchQueue.main.async {
        var b: Int = 3
        a = b
    }

    // wait until the task finishes, then print 

    print(a) // - this will contain nil, of course, because it
             // will execute before the code above

}

मैं Xcode 8.2 का उपयोग कर रहा हूं और स्विफ्ट 3 में लिख रहा हूं।

जवाबों:


229

DispatchGroupइसे प्राप्त करने के लिए s का उपयोग करें। समूह के कॉल enter()और leave()कॉल संतुलित होने पर आप या तो अधिसूचित हो सकते हैं:

func myFunction() {
    var a: Int?

    let group = DispatchGroup()
    group.enter()

    DispatchQueue.main.async {
        a = 1
        group.leave()
    }

    // does not wait. But the code in notify() gets run 
    // after enter() and leave() calls are balanced

    group.notify(queue: .main) {
        print(a)
    }
}

या आप इंतजार कर सकते हैं:

func myFunction() {
    var a: Int?

    let group = DispatchGroup()
    group.enter()

    // avoid deadlocks by not using .main queue here
    DispatchQueue.global(attributes: .qosDefault).async {
        a = 1
        group.leave()
    }

    // wait ...
    group.wait()

    print(a) // you could also `return a` here
}

नोट : group.wait()वर्तमान कतार (संभवतः आपके मामले में मुख्य कतार) को अवरुद्ध करता है, इसलिए आपको गतिरोधdispatch.async से बचने के लिए दूसरी कतार (जैसे ऊपर के नमूना कोड में) पर होना चाहिए ।


मैं दूसरी कक्षा में एक फ़ंक्शन निष्पादित करना चाहता हूं, लेकिन मैं उस फ़ंक्शन को समाप्त करने के लिए इंतजार करना चाहता हूं और फिर वर्तमान कक्षा में जारी रखता हूं कि मैं कैसे संभाल सकता हूं?
सईद रहमतोलाई

2
@SaeedRahmatolahi: या तो waitदृष्टिकोण का उपयोग करें (यदि यह आपके लिए ब्लॉक करने के लिए कोई समस्या नहीं है, यानी यदि आप मुख्य धागे पर नहीं हैं) या एक पूरा हैंडलर प्रदान करें या अपने कॉलिंग क्लास में सूचित दृष्टिकोण का उपयोग करें।
छिछोरापन

आप group.enterAsync ब्लॉक के बाहर कॉल क्यों करते हैं ? क्या समूह में प्रवेश करना और छोड़ना प्रत्येक ब्लॉक की जिम्मेदारी नहीं होनी चाहिए?
बिल

4
@ बिल आने waitतक इंतजार किया जाता है enterऔर leaveकॉल को संतुलित किया जाता है। आप डाल दिया enterबंद में, waitइंतजार नहीं करेंगे, क्योंकि enterअभी तक है और इस तरह की संख्या कहा जाता है नहीं किया गया है enterऔर leaveकॉल कर रहे हैं संतुलित (# == 0 दर्ज करें, # leav == 0)।
छिछला

1
परीक्षणों के लिए @rustyMagnet यह शायद जाने का रास्ता नहीं है। XCTTestExpectationइसके बजाय एस का उपयोग करें । यह नमूना कोड
19 को छिछला

26

स्विफ्ट 3 में, DispatchQueueएक कार्य पूरा करने पर हैंडलर को पूरा करने की कोई आवश्यकता नहीं है । इसके अलावा आप विभिन्न तरीकों से अपने लक्ष्य को प्राप्त कर सकते हैं

एक तरीका यह है:

    var a: Int?

    let queue = DispatchQueue(label: "com.app.queue")
    queue.sync {

        for  i in 0..<10 {

            print("Ⓜ️" , i)
            a = i
        }
    }

    print("After Queue \(a)")

यह तब तक इंतजार करेगा जब तक कि लूप खत्म नहीं हो जाता लेकिन इस मामले में आपका मुख्य धागा ब्लॉक हो जाएगा।

आप भी ऐसा ही कर सकते हैं:

    let myGroup = DispatchGroup()
    myGroup.enter()
    //// Do your task

    myGroup.leave() //// When your task completes
     myGroup.notify(queue: DispatchQueue.main) {

        ////// do your remaining work
    }

एक आखिरी बात: यदि आप अपने काम को डिस्पैचक्व्यू के इस्तेमाल से पूरा करना चाहते हैं, तो आप हैंडहेलर का उपयोग कर सकते हैं DispatchWorkItem

यहाँ एक उदाहरण है कि कैसे उपयोग किया जाए DispatchWorkItem:

let workItem = DispatchWorkItem {
    // Do something
}

let queue = DispatchQueue.global()
queue.async {
    workItem.perform()
}
workItem.notify(queue: DispatchQueue.main) {
    // Here you can notify you Main thread
}

1
मैंने उन सभी की कोशिश की और लूप के लिए

2

प्रेषण समूह का उपयोग करें

   dispatchGroup.enter()
   FirstOperation(completion: { _ in
dispatchGroup.leave()
  })
    dispatchGroup.enter()
    SecondOperation(completion: { _ in
dispatchGroup.leave()
  })
   dispatchGroup.wait() //Waits here on this thread until the two operations complete executing.

5
मान लें कि आप इसे मुख्य कतार में कहते हैं, तो यह गतिरोध पैदा करेगा।
उथला

@shallowThought इतना सच।
प्रेटेकरो

मैं दूसरी कक्षा में एक फ़ंक्शन निष्पादित करना चाहता हूं, लेकिन मैं उस फ़ंक्शन को समाप्त करने के लिए इंतजार करना चाहता हूं और फिर वर्तमान कक्षा में जारी रखता हूं कि मैं कैसे संभाल सकता हूं?
सईद रहमतोलाई

1
यद्यपि उपरोक्त उदाहरण मुख्य धागे पर ब्लॉक करेगा, जैसा कि पिछले उत्तरों ने दिखाया है, भीतर लपेटने DispatchQueue.global().async{}से मुख्य कतार अवरुद्ध नहीं होगी।
जॉनीब

2

समाधान के 5 संस्करण स्विफ्ट

func myCriticalFunction () {var value1: स्ट्रिंग? var value2: स्ट्रिंग?

let group = DispatchGroup()


group.enter()
//async operation 1
DispatchQueue.global(qos: .default).async { 
    // Network calls or some other async task
    value1 = //out of async task
    group.leave()
}


group.enter()
//async operation 2
DispatchQueue.global(qos: .default).async {
    // Network calls or some other async task
    value2 = //out of async task
    group.leave()
}


group.wait()

print("Value1 \(value1) , Value2 \(value2)") 

}


1

स्विफ्ट 4

आप इन स्थितियों के लिए Async फ़ंक्शन का उपयोग कर सकते हैं। जब आप उपयोग करते हैं DispatchGroup(), तो कभी-कभी गतिरोध भी हो सकता है।

var a: Int?
@objc func myFunction(completion:@escaping (Bool) -> () ) {

    DispatchQueue.main.async {
        let b: Int = 3
        a = b
        completion(true)
    }

}

override func viewDidLoad() {
    super.viewDidLoad()

    myFunction { (status) in
        if status {
            print(self.a!)
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.