1

I am trying to understand OperationQueue's and its advantages over the DispatchQueue. So when I learn dependencies between Operations I think I can use over the DispatchGroups but I am still trying to understand how can I make them wait for each other without using Semaphore or DispatchGroup

I started with:

let customQueue = OperationQueue()

let fetchIDOperation = Operation()
let fetchUserPhotoOperation = Operation()

customQueue.maxConcurrentOperationCount = 1

fetchUserPhotoOperation.completionBlock = {
    print("photos are fetching")
}

fetchIDOperation.completionBlock = {
    let url = URL.init(string: "http://jsonplaceholder.typicode.com/todos/1")!
    
    URLSession.shared.dataTask(with: url) { (data, _, err) in
        guard err == nil, let data = data else {
            print("err")
            return
        }
        
        let a = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
        print("json > ", a)
        
    }.resume()
    
}

fetchUserPhotoOperation.addDependency(fetchIDOperation)

customQueue.addOperation(fetchIDOperation)
customQueue.addOperation(fetchUserPhotoOperation)

fetchIDOperation.start()

The output is

ids are fetching
photos are fetching
json >  ["completed": 0, "userId": 1, "id": 1, "title": delectus aut autem]

I want that OperationQueue for photos one should start after the async task done in fetchIDOperation.

When I search for similar problems in Stackoverflow, in some answers there's referred to be using DispatchSemaphore. I really loved using the dependency functionality of the API, so is there an easy way to achieve this way without using semaphore or dispatchgroup?

Thanks in advance

eemrah
  • 1,603
  • 3
  • 19
  • 37
  • 1
    A real great explaination with a sample on working async queue (I used a inspired by it for that): https://www.avanderlee.com/swift/asynchronous-operations/ https://github.com/AvdLee/AsyncOperations – Larme Jan 14 '21 at 19:17
  • 1
    `Operation` is synchronous by default. If it contains an asynchronous task `isFinished` is called before the asynchronous task completes. Look at [this question](https://stackoverflow.com/questions/43561169/trying-to-understand-asynchronous-operation-subclass/43761518?). The answer of Rob describes an asynchronous version of `Operation` – vadian Jan 14 '21 at 19:18
  • huge thanks @vadian and @Larme, I started with analyzing mock `AsyncOperation` class of avanderlee, then I worked it out for my example. But I would love to ask if this is the right place. ```willChangeValue(forKey: "isFinished") lockQueue.sync(flags: [.barrier]) { _isFinished = newValue } didChangeValue(forKey: "isFinished")``` normally isFinished property is getOnly, is this hack safe? And why we have to use `willChangeValue(for:)` and `didChangeValue(for:)` functions? – eemrah Jan 14 '21 at 20:30
  • 1
    You don't need `willChangeValue` and `didChangeValue`. In Swift `dynamic` enables KVO. See the answer in the link in my first comment. I'm using this class myself in a few projects. – vadian Jan 14 '21 at 20:33
  • ```swift @objc private dynamic var state: OperationState { get { return stateQueue.sync { _state } } set { stateQueue.async(flags: .barrier) { self._state = newValue } } }``` yeah, I learned the true way of usage of `dynamic` thank you! – eemrah Jan 14 '21 at 20:35
  • I probably have a different opinion on OperationQueues. I would avoid it whenever possible and use plain GCD. The dependency feature is nice, however OperationQueues don't provide a mechanism to process the output from one operation within another (chaining output -> input). Even creating custom Operations _correctly_ is far more complicated than it ought to be. So, IMHO, you should only use OperationQueues once you are very familiar with GCD and know a lot of thread-safe programming. Alternatively, switch to Combine. – CouchDeveloper Jan 15 '21 at 11:16

0 Answers0