如何在Playground中运行异步回调

 禾漾啊 发布于 2023-01-11 15:07

许多Cocoa和CocoaTouch方法都有完成回调,实现为Objective-C中的块和Swift中的闭包.但是,在Playground中尝试这些时,永远不会调用完成.例如:

// Playground - noun: a place where people can play

import Cocoa
import XCPlayground

let 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?
    if let data = maybeData {
        let contents = NSString(data:data, encoding:NSUTF8StringEncoding)
        println(contents)
    } else {
        println(error.localizedDescription)
    }
}

我可以在我的Playground时间轴中看到控制台输出,但是println我的完成块永远不会被调用...

6 个回答
  • 不调用回调的原因是因为RunLoop没有在Playground中运行(或者在REPL模式下运行).

    使回调操作的一种有点笨拙但有效的方法是使用标志,然后在runloop上手动迭代:

    // Playground - noun: a place where people can play
    
    import Cocoa
    import XCPlayground
    
    let url = NSURL(string: "http://stackoverflow.com")
    let request = NSURLRequest(URL: url)
    
    var waiting = true
    
    NSURLConnection.sendAsynchronousRequest(request, queue:NSOperationQueue.currentQueue() {
    response, maybeData, error in
        waiting = false
        if let 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)
    }
    

    此模式通常用于需要测试异步回调的单元测试中,例如:用于单元测试的模式异步队列,在完成时调用主队列

    2023-01-11 15:08 回答
  • 从XCode 7.1开始,XCPSetExecutionShouldContinueIndefinitely()不推荐使用.现在执行此操作的正确方法是首先请求无限期执行作为当前页面的属性:

    import XCPlayground
    
    XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
    

    ...然后指示执行完成时间:

    XCPlaygroundPage.currentPage.finishExecution()
    

    例如:

    import Foundation
    import XCPlayground
    
    XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
    
    NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: "http://stackoverflow.com")!) {
        result in
        print("Got result: \(result)")
        XCPlaygroundPage.currentPage.finishExecution()
    }.resume()
    

    2023-01-11 15:08 回答
  • 此API在Xcode 8中再次更改,并且已移至PlaygroundSupport:

    import PlaygroundSupport
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    

    2016年WWDC会议213中提到了这一变化.

    2023-01-11 15:08 回答
  • Swift 4,Xcode 9.0

    import Foundation
    import PlaygroundSupport
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    
    let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")!
    
    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard error == nil else {
            print(error?.localizedDescription ?? "")
            return
        }
    
        if let data = data, let contents = String(data: data, encoding: String.Encoding.utf8) {
            print(contents)
        }
    }
    task.resume()
    

    2023-01-11 15:09 回答
  • 虽然您可以手动运行运行循环(或者,对于不需要运行循环的异步代码,使用其他等待方法,如调度信号量),我们在操场上提供的"内置"方式等待异步工作是导入XCPlayground框架并设置XCPlaygroundPage.currentPage.needsIndefiniteExecution = true.如果已设置此属性,当您的顶级游乐场源完成时,我们将继续旋转主运行循环,而不是停止操场,因此异步代码有机会运行.我们最终会在超时后终止操场,默认为30秒,但如果您打开助理编辑器并显示时间线助手,则可以配置; 超时在右下方.

    例如,在Swift 3中(使用URLSession代替NSURLConnection):

    import UIKit
    import PlaygroundSupport
    
    let url = URL(string: "http://stackoverflow.com")!
    
    URLSession.shared.dataTask(with: url) { data, response, error in
        guard let data = data, error == nil else {
            print(error ?? "Unknown error")
            return
        }
    
        let contents = String(data: data, encoding: .utf8)
        print(contents!)
    }.resume()
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    

    或者在Swift 2中:

    import UIKit
    import XCPlayground
    
    let url = NSURL(string: "http://stackoverflow.com")
    let request = NSURLRequest(URL: url!)
    
    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.currentQueue()) { response, maybeData, error in
        if let data = maybeData {
            let contents = NSString(data:data, encoding:NSUTF8StringEncoding)
            println(contents)
        } else {
            println(error.localizedDescription)
        }
    }
    
    XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
    

    2023-01-11 15:09 回答
  • XCode8,Swift3和iOS 10的新API是,

    // import the module
    import PlaygroundSupport
    // write this at the beginning
    PlaygroundPage.current.needsIndefiniteExecution = true
    // To finish execution
    PlaygroundPage.current.finishExecution()
    

    2023-01-11 15:09 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有