كيف يمكنني تشغيل الاستدعاءات غير المتزامنة في الملعب
-
26-12-2019 - |
سؤال
تم تنفيذ العديد من طرق الكاكاو والكوكواتوش ككتل في الهدف جيم والإغلاق في سويفت.ومع ذلك ، عند تجربة هذه الأشياء في الملعب ، لا يتم استدعاء الإكمال أبدا.على سبيل المثال:
// 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
في كتلة الانتهاء الخاصة بي لا تسمى أبدا...
المحلول
بينما يمكنك تشغيل حلقة تشغيل يدويا (أو ، بالنسبة للرمز غير المتزامن الذي لا يتطلب حلقة تشغيل ، استخدم طرق انتظار أخرى مثل إشارات الإرسال) ، فإن الطريقة "المضمنة" التي نقدمها في الملاعب لانتظار العمل غير المتزامن هي استيراد 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
نصائح أخرى
تغيرت هذه أبي مرة أخرى في كسكودي 8 وتم نقله إلى PlaygroundSupport
:
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
تم ذكر هذا التغيير في الجلسة 213 في مؤتمر القمة العالمي للتنمية المستدامة 2016.
اعتبارا من كسكودي 7.1, XCPSetExecutionShouldContinueIndefinitely()
تم إهماله.الطريقة الصحيحة للقيام بذلك الآن هي أولا طلب التنفيذ لأجل غير مسمى كخاصية للصفحة الحالية:
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
indicate ثم حدد متى انتهى التنفيذ مع:
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()
السبب في عدم استدعاء الاستدعاءات هو أن رونلوب لا يعمل في الملعب (أو في وضع ريبل لهذه المسألة).
وهناك طريقة جانكي إلى حد ما ، ولكنها فعالة ، لجعل عمليات الاسترجاعات تعمل مع العلم ومن ثم تكرار يدويا على رونلوب:
// 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)
}
غالبا ما تم استخدام هذا النمط في اختبارات الوحدة التي تحتاج إلى اختبار عمليات الاسترجاعات غير المتزامنة ، على سبيل المثال: نمط لقائمة انتظار اختبار الوحدة غير المتزامنة التي تستدعي قائمة الانتظار الرئيسية عند الانتهاء
واجهات برمجة التطبيقات الجديدة كما ل شكود 8 ، سويفت3 و يوس 10 هي,
// import the module
import PlaygroundSupport
// write this at the beginning
PlaygroundPage.current.needsIndefiniteExecution = true
// To finish execution
PlaygroundPage.current.finishExecution()
سويفت 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 ، كسكودي 8 ، دائرة الرقابة الداخلية 10
الحواشي:
أخبر المترجم أن ملف الملعب يتطلب"تنفيذ غير محدد"
إنهاء التنفيذ يدويا عبر مكالمة إلى PlaygroundSupport.current.completeExecution()
ضمن معالج الإكمال الخاص بك.
قد واجهت مشاكل مع دليل ذاكرة التخزين المؤقت ولحل هذا سوف تحتاج إلى إعادة إنشاء إيكاش يدويا.المفرد المشترك.
مثال:
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()