Muitos métodos Cocoa e CocoaTouch têm callbacks de conclusão implementados como blocos em Objective-C e Closures em Swift. No entanto, ao tentar isso no Playground, a conclusão nunca é chamada. Por exemplo:
// 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)}}
Posso ver a saída do console na linha do tempo do Playground, mas printlnno meu bloco de conclusão nunca são chamados ...
Embora você possa executar um loop de execução manualmente (ou, para código assíncrono que não requer um loop de execução, use outros métodos de espera como semáforos de despacho), a maneira "embutida" que fornecemos em playgrounds para esperar pelo trabalho assíncrono é importar a XCPlaygroundestrutura e definir XCPlaygroundPage.currentPage.needsIndefiniteExecution = true. Se essa propriedade tiver sido definida, quando sua fonte de playground de nível superior terminar, em vez de parar o playground lá, continuaremos a girar o loop de execução principal, para que o código assíncrono tenha a chance de ser executado. Eventualmente encerraremos o playground após um tempo limite que é de 30 segundos, mas que pode ser configurado se você abrir o editor assistente e mostrar o assistente de cronograma; o tempo limite está no canto inferior direito.
Por exemplo, em Swift 3 (usando em URLSessionvez de NSURLConnection):
Não se esqueça de ligar PlaygroundPage.current.finishExecution().
Glenn
36
A partir do XCode 7.1, XCPSetExecutionShouldContinueIndefinitely()está obsoleto. A maneira correta de fazer isso agora é primeiro solicitar a execução indefinida como uma propriedade da página atual:
importFoundationimportXCPlaygroundXCPlaygroundPage.currentPage.needsIndefiniteExecution =trueNSURLSession.sharedSession().dataTaskWithURL(NSURL(string:"http://stackoverflow.com")!){
result in
print("Got result: \(result)")XCPlaygroundPage.currentPage.finishExecution()}.resume()
A razão pela qual os callbacks não são chamados é porque o RunLoop não está rodando no Playground (ou no modo REPL para esse assunto).
Uma maneira um tanto janky, mas eficaz, de fazer os callbacks operarem é com um sinalizador e, em seguida, iterando manualmente no runloop:
// 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
estrutura agora está disponível para iOS Playgrounds também.XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
import PlaygroundSupport
ePlaygroundPage.current.needsIndefiniteExecution = true
Esta API mudou novamente no Xcode 8 e foi movida para
PlaygroundSupport
:Essa mudança foi mencionada na Sessão 213 no WWDC 2016 .
fonte
PlaygroundPage.current.finishExecution()
.A partir do XCode 7.1,
XCPSetExecutionShouldContinueIndefinitely()
está obsoleto. A maneira correta de fazer isso agora é primeiro solicitar a execução indefinida como uma propriedade da página atual:... então indique quando a execução terminar com:
Por exemplo:
fonte
A razão pela qual os callbacks não são chamados é porque o RunLoop não está rodando no Playground (ou no modo REPL para esse assunto).
Uma maneira um tanto janky, mas eficaz, de fazer os callbacks operarem é com um sinalizador e, em seguida, iterando manualmente no runloop:
Este padrão tem sido frequentemente usado em testes de unidade que precisam testar retornos de chamada assíncronos, por exemplo: Padrão para fila assíncrona de teste de unidade que chama a fila principal na conclusão
fonte
As novas APIs para XCode8, Swift3 e iOS 10 são,
fonte
Swift 4, Xcode 9.0
fonte
Swift 3, xcode 8, iOS 10
Notas:
Diga ao compilador que o arquivo do playground requer "execução indefinida"
Encerre manualmente a execução por meio de uma chamada para
PlaygroundSupport.current.completeExecution()
dentro de seu manipulador de conclusão.Você pode ter problemas com o diretório de cache e para resolver isso você precisará reinstanciar manualmente o singleton UICache.shared.
Exemplo:
fonte
fonte