How do I run Asynchronous callbacks in Playground

前端 未结 8 659
夕颜
夕颜 2020-11-22 11:38

Many Cocoa and CocoaTouch methods have completion callbacks implemented as blocks in Objective-C and Closures in Swift. However, when trying these out in Playground, the co

相关标签:
8条回答
  • 2020-11-22 11:51

    The reason the callbacks are not called is because the RunLoop isn't running in Playground (or in REPL mode for that matter).

    A somewhat janky, but effective, way to make the callbacks operate is with a flag and then manually iterating on the 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)
    }
    

    This pattern has often been used in Unit Tests which need to test async callbacks, for example: Pattern for unit testing async queue that calls main queue on completion

    0 讨论(0)
  • 2020-11-22 11:52
    NSURLConnection.sendAsynchronousRequest(...)    
    NSRunLoop.currentRunLoop().run()
    
    0 讨论(0)
  • 2020-11-22 12:00

    As of XCode 7.1, XCPSetExecutionShouldContinueIndefinitely() is deprecated. The correct way to do this now is to first request indefinite execution as a property of the current page:

    import XCPlayground
    
    XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
    

    …then indicate when execution has finished with:

    XCPlaygroundPage.currentPage.finishExecution()
    

    For example:

    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()
    
    0 讨论(0)
  • 2020-11-22 12:00

    Swift 3, xcode 8, iOS 10

    Notes:

    Tell the compiler that the playground file requires "indefinite execution"

    Manually terminate execution via a call to PlaygroundSupport.current.completeExecution() within your completion handler.

    You may run into problems with the cache directory and to resolve this you will need to manually re-instantiate the UICache.shared singleton.

    Example:

    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()
    
    0 讨论(0)
  • 2020-11-22 12:03

    This API changed again in Xcode 8 and it was moved to the PlaygroundSupport:

    import PlaygroundSupport
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    

    This change was mentioned in Session 213 at WWDC 2016.

    0 讨论(0)
  • 2020-11-22 12:05

    The new APIs as for XCode8, Swift3 and iOS 10 are,

    // import the module
    import PlaygroundSupport
    // write this at the beginning
    PlaygroundPage.current.needsIndefiniteExecution = true
    // To finish execution
    PlaygroundPage.current.finishExecution()
    
    0 讨论(0)
提交回复
热议问题