Есть ли конкретный способ добавить DispatchWorkItems к DispatchQueue вместо их объявления в коде?

У меня есть несколько рабочих элементов Dispatch для выполнения в очереди. Я не хочу повторно объявлять коды, я хочу передать их в массив или список DispatchWorkItems а затем добавить его в очередь отправки есть ли способ добиться этого?

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

/// КАК КОГДА-ЛИБО ХОЧУ ПОЛУЧИТЬ ЧТО-ТО, КАК ЭТО

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

// ЭТО ВОЗМОЖНО?

serialQueue.sync(execute: itemsToExecute) ?

1 ответ

Решение

Да, вы можете иметь массив DispatchWorkItem объекты, но чтобы отправить их все, вам нужно просто перебрать их, например, с for-in или же 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
}

Обратите внимание, я использовал async против syncпотому что весь смысл использования GCD состоит в том, чтобы избежать блокировки основной очереди, и при этом sync блоки, async не делает.

Возникает вопрос: зачем вам использовать массив DispatchWorkItem хотя на всех. Просто добавьте задачи в очередь напрямую, и очередь позаботится о том, чтобы отслеживать их все за вас.


Честно говоря, мы бы просто хотели использовать URLSession, Например:

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

Где возможно:

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

Затем вы можете сделать что-то вроде:

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")
}
Другие вопросы по тегам