programing

Playground에서 비동기 콜백을 실행하는 방법

i4 2023. 9. 3. 12:11
반응형

Playground에서 비동기 콜백을 실행하는 방법

많은 코코아와 코코아터치 방식은 목표-C와 스위프트의 폐쇄에서 완료 콜백을 블록으로 구현합니다.그러나 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내가 완성할 때는 절대...라고 불리지 않습니다.

실행 루프를 수동으로 실행할 수 있지만(또는 실행 루프가 필요하지 않은 비동기 코드의 경우 디스패치 세마포와 같은 다른 대기 방법을 사용), 우리가 놀이터에서 제공하는 비동기 작업을 대기하는 "내장" 방식은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

이 API는 Xcode 8에서 다시 변경되었으며 다음으로 이동되었습니다.PlaygroundSupport:

import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

이 변화는 WWDC 2016의 세션 213에서 언급되었습니다.

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

콜백이 호출되지 않는 이유는 RunLoop이 Playground(또는 REPL 모드)에서 실행되고 있지 않기 때문입니다.

콜백을 작동시키는 다소 번거롭지만 효과적인 방법은 플래그를 사용한 다음 실행 루프에서 수동으로 반복하는 것입니다.

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

이 패턴은 비동기 콜백을 테스트해야 하는 장치 테스트에서 자주 사용되었습니다. 를 들어, 완료 시대기열을 호출하는 장치 테스트용 패턴입니다.

XCode8, Swift3, iOS10에 대한 새로운 API는 다음과 같습니다.

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

스위프트 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()

스위프트 3, xcode 8, iOS 10

주의:

컴파일러에게 플레이그라운드 파일에 "무기한 실행"이 필요하다고 말합니다.

을 통수로실종으로 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()
NSURLConnection.sendAsynchronousRequest(...)    
NSRunLoop.currentRunLoop().run()

언급URL : https://stackoverflow.com/questions/24058336/how-do-i-run-asynchronous-callbacks-in-playground

반응형