Asynchronous 如何在操场上运行异步回调

Asynchronous 如何在操场上运行异步回调,asynchronous,callback,closures,swift,swift-playground,Asynchronous,Callback,Closures,Swift,Swift Playground,许多Cocoa和CoCoatTouch方法在Objective-C中以块的形式实现完成回调,在Swift中以闭包的形式实现。然而,当在操场上尝试这些游戏时,永远不会要求完成。例如: // Playground - noun: a place where people can play import Cocoa import XCPlayground let url = NSURL(string: "http://stackoverflow.com") let request = NSURLR

许多Cocoa和CoCoatTouch方法在Objective-C中以块的形式实现完成回调,在Swift中以闭包的形式实现。然而,当在操场上尝试这些游戏时,永远不会要求完成。例如:

// 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)
    }
}
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()

我可以在我的游乐场时间轴中看到控制台输出,但我的完成块中的
println
从未被调用

不调用回调的原因是RunLoop没有在操场上运行(或者在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)
}

此模式通常用于需要测试异步回调的单元测试中,例如:

不调用回调的原因是因为RunLoop没有在操场上运行(或者在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)
}

此模式通常用于需要测试异步回调的单元测试中,例如:

当您可以手动运行运行循环时(或者,对于不需要运行循环的异步代码,使用其他等待方法,如调度信号量),“内置”我们在操场中提供的等待异步工作的方法是导入
XCPlaygroundPage
框架并设置
XCPlaygroundPage.currentPage.needsIndefiniteExecution=true
。如果设置了这个属性,当顶级游乐场源代码完成时,我们将继续旋转主运行循环,而不是停止游乐场,这样异步代码就有机会运行。我们最终将在默认为30秒的超时后终止游乐场,但如果您打开助手编辑器并显示时间线助手,则可以对其进行配置;超时在右下角

例如,在Swift 3中(使用
URLSession
而不是
NSURLConnection
):

或在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

虽然您可以手动运行运行循环(或者,对于不需要运行循环的异步代码,可以使用其他等待方法,如调度信号量),但“内置”我们在操场中提供的等待异步工作的方法是导入
XCPlaygroundPage
框架并设置
XCPlaygroundPage.currentPage.needsIndefiniteExecution=true
。如果设置了这个属性,当顶级游乐场源代码完成时,我们将继续旋转主运行循环,而不是停止游乐场,这样异步代码就有机会运行。我们最终将在默认为30秒的超时后终止游乐场,但如果您打开助手编辑器并显示时间线助手,则可以对其进行配置;超时在右下角

例如,在Swift 3中(使用
URLSession
而不是
NSURLConnection
):

或在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

从XCode 7.1开始,
XcpsetExecutionShouldContinueIndefinite()
已被弃用。现在正确的方法是首先请求无限期执行作为当前页面的属性:

import XCPlayground

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
…然后指示执行完成的时间,包括:

XCPlaygroundPage.currentPage.finishExecution()
例如:

// 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)
    }
}
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()

从XCode 7.1开始,
XcpsetExecutionShouldContinueIndefinite()
已被弃用。现在正确的方法是首先请求无限期执行作为当前页面的属性:

import XCPlayground

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
…然后指示执行完成的时间,包括:

XCPlaygroundPage.currentPage.finishExecution()
例如:

// 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)
    }
}
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()

此API在Xcode 8中再次更改,并被移动到
PlaygroundSupport

import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

此更改在中提到。

此API在Xcode 8中再次更改,并移动到
PlaygroundSupport

import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

此更改在中提到。

针对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()

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()

Swift 3、xcode 8、iOS 10

注意事项:

import UIKit
import Foundation
import PlaygroundSupport

// resolve path errors
URLCache.shared = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)

// identify that the current page requires "indefinite execution"
PlaygroundPage.current.needsIndefiniteExecution = true

// encapsulate execution completion
func completeExecution() {
    PlaygroundPage.current.finishExecution()
}

let url = URL(string: "http://i.imgur.com/aWkpX3W.png")

let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
    var image = UIImage(data: data!)

    // complete execution
    completeExecution()
}

task.resume()
告诉编译器游乐场文件需要“无限执行”

通过在完成处理程序中调用
PlaygroundSupport.current.completeExecution()
手动终止执行

缓存目录可能会出现问题,要解决此问题,需要手动重新实例化UICache.shared singleton

示例:

import UIKit
import Foundation
import PlaygroundSupport

// resolve path errors
URLCache.shared = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)

// identify that the current page requires "indefinite execution"
PlaygroundPage.current.needsIndefiniteExecution = true

// encapsulate execution completion
func completeExecution() {
    PlaygroundPage.current.finishExecution()
}

let url = URL(string: "http://i.imgur.com/aWkpX3W.png")

let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
    var image = UIImage(data: data!)

    // complete execution
    completeExecution()
}

task.resume()

Swift 3、xcode 8、iOS 10

注意事项:

import UIKit
import Foundation
import PlaygroundSupport

// resolve path errors
URLCache.shared = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)

// identify that the current page requires "indefinite execution"
PlaygroundPage.current.needsIndefiniteExecution = true

// encapsulate execution completion
func completeExecution() {
    PlaygroundPage.current.finishExecution()
}

let url = URL(string: "http://i.imgur.com/aWkpX3W.png")

let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
    var image = UIImage(data: data!)

    // complete execution
    completeExecution()
}

task.resume()
告诉编译器游乐场文件需要“无限执行”

通过在完成处理程序中调用
PlaygroundSupport.current.completeExecution()
手动终止执行

缓存目录可能会出现问题,要解决此问题,需要手动重新实例化UICache.shared singleton

示例:

import UIKit
import Foundation
import PlaygroundSupport

// resolve path errors
URLCache.shared = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)

// identify that the current page requires "indefinite execution"
PlaygroundPage.current.needsIndefiniteExecution = true

// encapsulate execution completion
func completeExecution() {
    PlaygroundPage.current.finishExecution()
}

let url = URL(string: "http://i.imgur.com/aWkpX3W.png")

let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
    var image = UIImage(data: data!)

    // complete execution
    completeExecution()
}

task.resume()

Swift 4,Xcode 9.0

<代码>导入基础 导入PlaygroundSupport PlaygroundPage.current.NeedsDefiniteExecution=true 让url=url(字符串:https://jsonplaceholder.typicode.com/posts/1")! 让task=URLSession.shared.dataTask(带:url){(数据、响应、错误)在 保护错误==nil else{ 打印(错误?.localizedDescription??) 返回 } 如果let data=data,则let contents=String(数据:data,编码:String.encoding.utf8){ 印刷品(目录) } } task.resume()
Swift 4,Xcode 9.0

<代码>导入基础 导入PlaygroundSupport PlaygroundPage.current.NeedsDefiniteExecution=true 让url=url(字符串:https://jsonplaceholder.typicode.com/posts/1")! 让task=URLSession.shared.dataTask(带:url){(数据、响应、错误)在 保护错误==nil else{ 打印(错误?.localizedDescription??) 返回 } 如果let data=data,则let contents=String(数据:data,编码:String.encoding.utf8){ 印刷品(目录) } } task.resume()
2014年世界野生动植物保护大会(WWDC)对此作了详细介绍?