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
'programing' 카테고리의 다른 글
부트스트랩 모드: 함수가 아닙니다. (0) | 2023.09.08 |
---|---|
스트림에서 Zip 파일 생성 및 다운로드 (0) | 2023.09.03 |
Oracle과 대체 스키마의 외부 키? (0) | 2023.09.03 |
$.ajax url을 사용하여 여러 매개 변수 전달 (0) | 2023.09.03 |
Angular 2 상태의 파이프 (0) | 2023.09.03 |