В разработке Swift/Objective-C есть три простых и полностью ожидаемых подхода к этой проблеме, и ни одно из этих решений не включает метод, возвращающий значение напрямую. Вы можете написать код, который ожидает завершения асинхронной части (блокируя поток), а затем возвращает значение, и в некоторых случаях это делается в некоторых собственных библиотеках Apple, но я не собираюсь рассказать о подходе, потому что на самом деле это не очень хорошая идея.
Первый подход включает в себя блоки завершения.
Когда наш метод будет выполнять некоторый асинхронный код, мы можем передать блок кода для выполнения всякий раз, когда выполняется асинхронная работа. Такой метод будет выглядеть следующим образом:
func asynchStuff(completionHandler: ([String:String]) -> Void) {
// do asynchronous stuff, building a [String:String]
let result: [String: String] = // the result we got async
completionHandler(result)
}
Не забудьте вызвать completionHandler()
в том же потоке, в котором был вызван asynchStuff
. (Этот пример не демонстрирует этого.)
Второй подход включает делегатов и протоколы.
Нам нужен класс для выполнения асинхронной работы. Этот класс будет содержать ссылку на наш делегат, который будет реализовывать методы завершения. Сначала протокол:
@objc protocol AsyncDelegate {
func complete(result: [String:String]
}
Теперь наш асинхронный рабочий:
class AsyncWorker {
weak var delegate: AsyncDelegate?
func doAsyncWork() {
// like before, do async work...
let result: [String: String] = // the result we got async
self.delegate?.complete(result)
}
}
Не забудьте убедиться, что мы вызываем метод делегата завершения в том же потоке, в котором был вызван doAsyncWork()
. (Этот пример не демонстрирует этого.)
Третий подход можно реализовать с помощью NSNotificationCenter
. Времена, когда это подходящий подход, будут настолько редки, что я даже не буду утруждать себя даже рудиментарным примером, как я сделал два других примера, потому что вы почти наверняка должны использовать один из первых двух примеров в почти каждый сценарий.
Какой подход вы используете, полностью зависит от вашего конкретного варианта использования. В Objective-C я часто предпочитал делегирование блочному подходу (хотя иногда блоки правильны), но Swift позволяет нам передавать обычные функции/методы в качестве нашего блочного аргумента, поэтому он немного склоняет меня к использованию блочного подхода для Swift. , но тем не менее, используйте правильный инструмент для правильной работы, как всегда.
Я хотел расширить этот ответ, чтобы обратиться к обратному вызову (будь то блоки или делегаты) в соответствующем потоке. Я не уверен, есть ли способ сделать это с помощью GCD, но мы можем сделать это с помощью NSOperationQueue
s.
func asyncStuff(completionHandler: ([String:String]) -> Void) {
let currentQueue = NSOperationQueue.currentQueue()
someObject.doItsAsyncStuff(someArg, completion: {
result: [String:String] in
currentQueue.addOperationWithBlock() {
completionHandler(result)
}
}
}
person
nhgrif
schedule
27.06.2015