Is there a specific way to append DispatchWorkItems to a DispatchQueue instead of re declaring them in code?

大憨熊 提交于 2019-12-08 09:31:17

问题


I have several Dispatch work items to execute on a queue i don't want to redeclare the codes, i want to pass them to an array or list of DispatchWorkItems and then inject it to a dispatch queue is there any way to achieve this ?

    func executeDispatchWorkItem(url: String, completion  : @escaping  (Result<String,Error>)-> Void,beganHandler  : @escaping  (String)-> Void){

do {
    beganHandler("\(url) Began to execute ")
    let content = try String(contentsOf:URL(string: url)!)
    completion(.success(content))
}
catch let error {
        completion(.failure(error))
}
sleep(1)

 }

   var serialQueue = DispatchQueue(label: "A queue")

  serialQueue.async {
executeDispatchWorkItem(url: "https://www.google.com/",completion: 
{data in

    switch data {
    case .success(let data):
        print("URL : \(data) completed  with \(String(describing: data))")
    case .failure(let error ):
        print("URL : \(error.localizedDescription) failed  with \(error.localizedDescription)")
    }

}, beganHandler: { me in
        print("\(me) began to execute ")
})

executeDispatchWorkItem(url: "www.facebook.com",completion: {data in

    switch data {
    case .success(let data):
        print("URL : \(data) completed  with \(String(describing: 
data))")
    case .failure(let error ):
        print("URL : \(error.localizedDescription) failed  with \(error.localizedDescription)")
    }

}, beganHandler: { me in
        print("\(me) began to execute ")
})
executeDispatchWorkItem(url: "www.youtube.com",completion: {data in

    switch data {
    case .success(let data):
        print("URL : \(data) completed  with \(String(describing: data))")
    case .failure(let error ):
        print("URL : \(error.localizedDescription) failed  with \(error.localizedDescription)")
    }

}, beganHandler: { me in
        print("\(me) began to execute ")
})

/// HOW EVER I WANT TO ACHIEVE SOMETHING LIKE THIS

let itemsToExecute : [DispatchWorkItem] = [dispatch1.dispatch2]

// IS THIS POSSIBLE ?

serialQueue.sync(execute: itemsToExecute) ?

回答1:


Yes, you can have an array of DispatchWorkItem objects, but to dispatch them all, you’d just have to iterate through them, e.g., with either for-in or forEach:

let queue = DispatchQueue(label: "com.domain.app.requests")
let group = DispatchGroup()

let itemsToExecute: [DispatchWorkItem] = [item1, item2]

itemsToExecute.forEach { queue.async(group: group, execute: $0) }

group.notify(queue: .main) {
    print("all done")         // this is called when the requests are done
}

Note, I used async vs sync, because the whole point of using GCD is to avoid blocking the main queue, and while sync blocks, async doesn’t.

This begs the question of why you’d bother using an array of DispatchWorkItem at all, though. Just add the tasks to the queue directly, and the queue takes care of keeping track of all of them for you.


Frankly, we’d probably just want to use URLSession. For example:

@discardableResult
func request(from urlString: String, completion: @escaping  (Result<String,Error>) -> Void) -> URLSessionTask {
    let task = URLSession.shared.dataTask(with: URL(string: urlString)!) { data, response, error in
        guard let data = data, error == nil else {
            completion(.failure(error!))
            return
        }

        guard
            let httpResponse = response as? HTTPURLResponse,
            200..<300 ~= httpResponse.statusCode
        else {
            completion(.failure(NetworkError.invalidResponse(data, response)))
            return
        }

        guard let string = String(data: data, encoding: .utf8) else {
            completion(.failure(NetworkError.nonStringBody))
            return
        }

        completion(.success(string))
    }
    task.resume()
    return task
}

Where perhaps:

enum NetworkError: Error {
    case invalidResponse(Data, URLResponse?)
    case nonStringBody
}

Then, you can do something like:

for urlString in urlStrings {
    group.enter()
    request(from: urlString) { result in
        defer { group.leave() }

        switch result {
        case .failure(let error):
            print(urlString, error)

        case .success(let string):
            print(urlString, string.count)
        }
    }
}

group.notify(queue: .main) {
    print("all done")
}


来源:https://stackoverflow.com/questions/57137326/is-there-a-specific-way-to-append-dispatchworkitems-to-a-dispatchqueue-instead-o

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!