मैं खेल के मैदान में अतुल्यकालिक कॉलबैक कैसे चलाऊं


117

कई कोको और कोकोआटच विधियों में स्विफ्ट में उद्देश्य-सी और क्लोजर में ब्लॉक के रूप में कार्यान्वित कॉलबैक पूरा होता है। हालाँकि, जब प्लेग्राउंड में इनकी कोशिश करते हैं, तो पूरा होने को कभी नहीं कहा जाता है। उदाहरण के लिए:

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

मैं अपने प्लेग्राउंड टाइमलाइन में कंसोल आउटपुट को देख सकता हूं, लेकिन printlnमेरे पूर्ण ब्लॉक में कभी भी कॉल नहीं किया जाता ...

जवाबों:


186

जब आप मैन्युअल रूप से एक रन लूप चला सकते हैं (या, एसिंक्रोनस कोड के लिए जो एक रन लूप की आवश्यकता नहीं है, अन्य प्रतीक्षा विधियों जैसे डिस्पैच सेमाफोर का उपयोग करें), "अंतर्निहित" तरीके से हम खेल के मैदानों में अतुल्यकालिक काम के लिए प्रतीक्षा करते हैं। XCPlaygroundफ्रेमवर्क और सेट आयात करें XCPlaygroundPage.currentPage.needsIndefiniteExecution = true। यदि यह संपत्ति सेट की गई है, जब आपका शीर्ष स्तर का खेल का मैदान स्रोत खत्म हो जाता है, तो खेल के मैदान को रोकने के बजाय हम मुख्य रन लूप को स्पिन करना जारी रखेंगे, इसलिए अतुल्यकालिक कोड को चलाने का मौका है। हम अंत में खेल के मैदान को समाप्त कर देंगे एक समय समाप्ति के बाद जो 30 सेकंड तक चूकता है, लेकिन जिसे आप सहायक संपादक को खोलते हैं और समयरेखा सहायक को दिखा सकते हैं; टाइमआउट निचले-दाएं में है।

उदाहरण के लिए, स्विफ्ट 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

या स्विफ्ट 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

1
इसके लायक सभी के लिए, यह WWDC 2014 :408 में शामिल है: स्विफ्ट प्लेग्राउंड, दूसरा हाफ
क्रिस कॉनओवर

3
यह देखते हुए कि DP4 से XCPlaygroundअब iOS Playgrounds के लिए भी फ्रेमवर्क उपलब्ध है।
ikuramedia

4
अपडेटेड विधि:XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
आर मेनके

23
अद्यतित विधि: import PlaygroundSupportऔरPlaygroundPage.current.needsIndefiniteExecution = true
सिंपलजी

48

यह API Xcode 8 में फिर से बदल गया और इसे यहां ले जाया गया PlaygroundSupport:

import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

डब्ल्यूडब्ल्यूडीसी 2016 में सत्र 213 में इस बदलाव का उल्लेख किया गया था ।


2
कॉल करने के लिए मत भूलना PlaygroundPage.current.finishExecution()
ग्लेन

36

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

16

कॉलबैक को नहीं कहा जाता है इसका कारण यह है कि 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)
}

इस पैटर्न का उपयोग अक्सर यूनिट टेस्ट में किया जाता है, जो async कॉलबैक का परीक्षण करने की आवश्यकता होती है, उदाहरण के लिए: यूनिट परीक्षण के लिए पैटर्न async कतार जो पूरा होने पर मुख्य कतार कहता है


8

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

5

स्विफ्ट 4, एक्सकोड 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

स्विफ्ट 3, एक्सकोड 8, आईओएस 10

टिप्पणियाँ:

संकलक को बताएं कि खेल के मैदान की फाइल को "अनिश्चित निष्पादन" की आवश्यकता है

PlaygroundSupport.current.completeExecution()अपने पूर्ण हैंडलर के भीतर कॉल के माध्यम से मैन्युअल रूप से निष्पादन को समाप्त करें ।

आप कैश निर्देशिका के साथ समस्याओं में भाग सकते हैं और इसे हल करने के लिए आपको UICache.sared 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()

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.