Как запустить асинхронные обратные вызовы на игровой площадке
117
Многие методы Cocoa и CocoaTouch имеют обратные вызовы завершения, реализованные как блоки в Objective-C и Closures в Swift. Однако при испытании их на Playground завершение никогда не вызывается. Например:
// Playground - noun: a place where people can play
importCocoaimportXCPlaygroundlet url = NSURL(string:"http://stackoverflow.com")let request =NSURLRequest(URL: url)NSURLConnection.sendAsynchronousRequest(request, queue:NSOperationQueue.currentQueue(){
response, maybeData, error in// This block never gets called?
iflet data = maybeData {let contents =NSString(data:data, encoding:NSUTF8StringEncoding)
println(contents)}else{
println(error.localizedDescription)}}
Я вижу вывод консоли на моей временной шкале Playground, но printlnв моем блоке завершения никогда не вызывается ...
Хотя вы можете запустить цикл выполнения вручную (или, для асинхронного кода, который не требует цикла выполнения, используйте другие методы ожидания, такие как семафоры отправки), «встроенный» способ, который мы предлагаем на игровых площадках для ожидания асинхронной работы, заключается в том, чтобы импортировать XCPlaygroundфреймворк и установить XCPlaygroundPage.currentPage.needsIndefiniteExecution = true. Если это свойство было установлено, когда ваш исходный код игровой площадки верхнего уровня завершится, вместо остановки игровой площадки мы продолжим вращать основной цикл выполнения, чтобы у асинхронного кода была возможность запускаться. В конечном итоге мы закроем игровую площадку после тайм-аута, который по умолчанию составляет 30 секунд, но который можно настроить, если вы откроете помощник редактора и покажете помощника временной шкалы; время ожидания находится в правом нижнем углу.
Например, в Swift 3 (с использованием URLSessionвместо NSURLConnection):
Не забудь позвонить PlaygroundPage.current.finishExecution().
Гленн
36
Начиная с XCode 7.1, XCPSetExecutionShouldContinueIndefinitely()не рекомендуется. Правильный способ сделать это сейчас - сначала запросить неопределенное выполнение как свойство текущей страницы:
importFoundationimportXCPlaygroundXCPlaygroundPage.currentPage.needsIndefiniteExecution =trueNSURLSession.sharedSession().dataTaskWithURL(NSURL(string:"http://stackoverflow.com")!){
result in
print("Got result: \(result)")XCPlaygroundPage.currentPage.finishExecution()}.resume()
Причина, по которой обратные вызовы не вызываются, заключается в том, что RunLoop не работает в Playground (или в режиме REPL, если на то пошло).
Несколько дрянный, но эффективный способ заставить обратные вызовы работать - это установить флаг, а затем вручную выполнить итерацию цикла выполнения:
// Playground - noun: a place where people can play
importCocoaimportXCPlaygroundlet url = NSURL(string:"http://stackoverflow.com")let request =NSURLRequest(URL: url)var waiting =trueNSURLConnection.sendAsynchronousRequest(request, queue:NSOperationQueue.currentQueue(){
response, maybeData, error in
waiting =falseiflet data = maybeData {let contents =NSString(data:data, encoding:NSUTF8StringEncoding)
println(contents)}else{
println(error.localizedDescription)}}while(waiting){NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate:NSDate())
usleep(10)}
// import the module
importPlaygroundSupport// write this at the beginning
PlaygroundPage.current.needsIndefiniteExecution =true// To finish execution
PlaygroundPage.current.finishExecution()
XCPlayground
фреймворк теперь доступен и для игровых площадок iOS.XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
import PlaygroundSupport
andPlaygroundPage.current.needsIndefiniteExecution = true
Этот API снова изменился в Xcode 8 и был перемещен в
PlaygroundSupport
:Это изменение было упомянуто в Сессии 213 на WWDC 2016 .
источник
PlaygroundPage.current.finishExecution()
.Начиная с XCode 7.1,
XCPSetExecutionShouldContinueIndefinitely()
не рекомендуется. Правильный способ сделать это сейчас - сначала запросить неопределенное выполнение как свойство текущей страницы:… Затем укажите, когда выполнение закончилось:
Например:
источник
Причина, по которой обратные вызовы не вызываются, заключается в том, что RunLoop не работает в Playground (или в режиме REPL, если на то пошло).
Несколько дрянный, но эффективный способ заставить обратные вызовы работать - это установить флаг, а затем вручную выполнить итерацию цикла выполнения:
Этот шаблон часто использовался в модульных тестах, которые должны тестировать асинхронные обратные вызовы, например: Шаблон для модульного тестирования асинхронной очереди, которая вызывает основную очередь по завершении
источник
Новые API для XCode8, Swift3 и iOS 10:
источник
Swift 4, Xcode 9.0
источник
Swift 3, xcode 8, iOS 10
Ноты:
Сообщите компилятору, что файл игровой площадки требует "неопределенного выполнения"
Завершите выполнение вручную с помощью вызова
PlaygroundSupport.current.completeExecution()
обработчика завершения.Вы можете столкнуться с проблемами с каталогом кеша, и для решения этого вам потребуется вручную повторно создать экземпляр синглтона UICache.shared.
Пример:
источник
источник