Jak uruchomić asynchroniczne wywołania zwrotne w Playground
117
Wiele metod Cocoa i CocoaTouch ma wywołania zwrotne zakończenia zaimplementowane jako bloki w Objective-C i Closures w Swift. Jednak podczas wypróbowywania ich w Playground zakończenie nigdy nie jest wywoływane. Na przykład:
// 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)}}
Widzę wyjście konsoli na mojej osi czasu Playground, ale printlnw moim bloku ukończenia nigdy nie są wywoływane ...
Chociaż pętlę uruchamiania można uruchomić ręcznie (lub w przypadku kodu asynchronicznego, który nie wymaga pętli uruchamiania, można użyć innych metod oczekiwania, takich jak semafory wysyłające), „wbudowanym” sposobem, który zapewniamy w placach zabaw, aby czekać na pracę asynchroniczną jest zaimportuj XCPlaygroundframework i ustawXCPlaygroundPage.currentPage.needsIndefiniteExecution = true . Jeśli ta właściwość została ustawiona, po zakończeniu działania źródła najwyższego poziomu placu zabaw zamiast zatrzymywania tamtejszego placu zabaw będziemy nadal obracać główną pętlę uruchamiania, aby kod asynchroniczny miał szansę zostać uruchomiony. Ostatecznie zamkniemy plac zabaw po upływie limitu czasu, który wynosi domyślnie 30 sekund, ale który można skonfigurować, otwierając edytor asystenta i wyświetlając asystenta osi czasu; limit czasu znajduje się w prawym dolnym rogu.
Na przykład w Swift 3 (używając URLSessionzamiast NSURLConnection):
Nie zapomnij zadzwonić PlaygroundPage.current.finishExecution().
Glenn,
36
Od XCode 7.1 XCPSetExecutionShouldContinueIndefinitely()jest przestarzały. Prawidłowym sposobem na to teraz jest zażądanie nieokreślonego wykonania jako właściwości bieżącej strony:
… Następnie wskaż, kiedy zakończyło się wykonywanie:
XCPlaygroundPage.currentPage.finishExecution()
Na przykład:
importFoundationimportXCPlaygroundXCPlaygroundPage.currentPage.needsIndefiniteExecution =trueNSURLSession.sharedSession().dataTaskWithURL(NSURL(string:"http://stackoverflow.com")!){
result in
print("Got result: \(result)")XCPlaygroundPage.currentPage.finishExecution()}.resume()
Powodem, dla którego wywołania zwrotne nie są wywoływane, jest to, że RunLoop nie działa w Playground (lub w trybie REPL).
Nieco dziwacznym, ale skutecznym sposobem na wywołanie funkcji zwrotnych jest użycie flagi, a następnie ręczne iterowanie w pętli uruchamiania:
// 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()
Powiedz kompilatorowi, że plik placu zabaw wymaga „nieokreślonego wykonania”
Ręcznie zakończ wykonywanie za pomocą wywołania PlaygroundSupport.current.completeExecution()w programie obsługi zakończenia.
Możesz napotkać problemy z katalogiem pamięci podręcznej i aby je rozwiązać, będziesz musiał ręcznie ponownie utworzyć instancję singletona UICache.shared.
XCPlayground
framework jest teraz dostępny również dla iOS Playgrounds.XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
import PlaygroundSupport
iPlaygroundPage.current.needsIndefiniteExecution = true
Ten interfejs API zmienił się ponownie w Xcode 8 i został przeniesiony do
PlaygroundSupport
:Ta zmiana została wspomniana w sesji 213 na WWDC 2016 .
źródło
PlaygroundPage.current.finishExecution()
.Od XCode 7.1
XCPSetExecutionShouldContinueIndefinitely()
jest przestarzały. Prawidłowym sposobem na to teraz jest zażądanie nieokreślonego wykonania jako właściwości bieżącej strony:… Następnie wskaż, kiedy zakończyło się wykonywanie:
Na przykład:
źródło
Powodem, dla którego wywołania zwrotne nie są wywoływane, jest to, że RunLoop nie działa w Playground (lub w trybie REPL).
Nieco dziwacznym, ale skutecznym sposobem na wywołanie funkcji zwrotnych jest użycie flagi, a następnie ręczne iterowanie w pętli uruchamiania:
Ten wzorzec był często używany w testach jednostkowych, które muszą testować asynchroniczne wywołania zwrotne, na przykład: wzorzec do testów jednostkowych kolejka asynchroniczna, która wywołuje kolejkę główną po zakończeniu
źródło
Nowe API jak dla XCode8, Swift3 i iOS 10 to:
źródło
Swift 4, Xcode 9.0
źródło
Swift 3, Xcode 8, iOS 10
Uwagi:
Powiedz kompilatorowi, że plik placu zabaw wymaga „nieokreślonego wykonania”
Ręcznie zakończ wykonywanie za pomocą wywołania
PlaygroundSupport.current.completeExecution()
w programie obsługi zakończenia.Możesz napotkać problemy z katalogiem pamięci podręcznej i aby je rozwiązać, będziesz musiał ręcznie ponownie utworzyć instancję singletona UICache.shared.
Przykład:
źródło
źródło