Есть ли конкретный способ добавить 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")
}