Swift学习-解决Playground 不能异步回调

1,211 阅读3分钟

这是我参与更文挑战的第30天,活动详情查看: 更文挑战

前言

自从简单学习如何在在 Playground 上写代码之后,让我学习的swift 热情的都高涨不少。从基础语法 StringClassFunction 一直学习到了swift的一些高级特性:闭包(Closures) ,Codable,反射(Mirror),Combine

image.png

但学习到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天技术文章分享;特别是对于没有任何文章存量又是新晋奶爸的我来说,最开始坚持真的挺痛苦的,只能等娃睡了之后,逼迫自己自己对于当天的学习做总结或者学习新的技能再来分享;但回过头来看,每天其实是比较充实的,摸鱼的机会少了,认真思考的时间多了,就连打字的速度和准确性都提高了。感谢掘金发起这个计划。 后面也会不定期进行更新分享,毕竟写文章感觉对于自己来说已经不是一件可怕的事情了。

参考

www.jianshu.com/p/8b37c3ef6…