这是我参与更文挑战的第30天,活动详情查看: 更文挑战
前言
自从简单学习如何在在 Playground 上写代码之后,让我学习的swift 热情的都高涨不少。从基础语法 String, Class,Function 一直学习到了swift的一些高级特性:闭包(Closures) ,Codable,反射(Mirror),Combine;
但学习到Combine+Networking的时候遇到了一个抓狂的问题:我写的异步网络请求怎么都获取不到响应结果; 最开始怀疑是我写的Combine有问题,毕竟刚学Combine,Combine是RX Swift的替代品,学起来也是有些难度的; 下面是我的代码
var storage = Set<AnyCancellable>()
let url = URL(string:"https://jsonplaceholder.typicode.com/posts/1")!
URLSession.shared.dataTaskPublisher(for: url).map { tuple -> Data in //tuple的类型为(data:Data,response:URLResponse)
// print("tuple:\(tuple)")
return tuple.data
}.sink { completion in
print(completion)
} receiveValue: { data in
print(data.description)
let resonpseStr = String(data: data, encoding: .utf8)
print("数据打印data:\(resonpseStr)")
}.store(in: &storage)
代码已经是一个不能再简单的请求了,但数据打印data:
始终得不到执行
猜想:Playground请求执行完毕后,对象被释放掉了,所以获取不到异步的回调了
后面确实也证明我的想法是对的!
通过一阵百度+google 确实有很多人都遇到同样的问题;
具体原因是这样的:
Playground中异步执行
Playground 中的代码是顶层代码(top-level code),也就是它是在于全局作用域中的。这些代码将会从上到下执行,并在执行完毕之后立即停止。
我们的异步回调代码一般都无法在程序结束之前获得执行,因此如果我们在 Playground 执行网络,或者其它耗时的异步操作,都无法获得我们想要的结果
为了让程序在代码执行结束后继续执行,我们可以使用如下代码:
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
这句代码会让 Playground 永远执行下去 ,当我们获取了需要的结果后,可以使用XCPlaygroundPage.currentPage.finishExecution()
停止 Playground 的执行:
解决问题
修正下我们的网络代码
import Foundation
import Combine
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
var storage = Set<AnyCancellable>()
let url = URL(string:"https://jsonplaceholder.typicode.com/posts/1")!
URLSession.shared.dataTaskPublisher(for: url).map { tuple -> Data in //tuple的类型为(data:Data,response:URLResponse)
// print("tuple:\(tuple)")
return tuple.data
}.sink { completion in
print(completion)
} receiveValue: { data in
print(data.description)
let resonpseStr = String(data: data, encoding: .utf8)
print("数据打印data:\(resonpseStr)")
// 在异步回调中调用结束循环
PlaygroundPage.current.finishExecution()
}.store(in: &storage)
成功获取到网络数据
[Combine.AnyCancellable]
292 bytes
data:Optional("{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"sunt aut facere repellat provident occaecati excepturi optio reprehenderit\",\n \"body\": \"quia et suscipit\\nsuscipit recusandae consequuntur expedita et cum\\nreprehenderit molestiae ut ut quas totam\\nnostrum rerum est autem sunt rem eveniet architecto\"\n}")
注意记得导入import PlaygroundSupport
,在异步回调中PlaygroundPage.current.finishExecution()
结束循环
总结
Playground 中还有很多其它的高级功能值得去探索,给自己挖一个坑,再出一个全一点的Playground使用教程;
小感言
很难想象这是自己连续第30天技术文章分享;特别是对于没有任何文章存量又是新晋奶爸的我来说,最开始坚持真的挺痛苦的,只能等娃睡了之后,逼迫自己自己对于当天的学习做总结或者学习新的技能再来分享;但回过头来看,每天其实是比较充实的,摸鱼的机会少了,认真思考的时间多了,就连打字的速度和准确性都提高了。感谢掘金发起这个计划。 后面也会不定期进行更新分享,毕竟写文章感觉对于自己来说已经不是一件可怕的事情了。