说明

异步操作使您可以编写长时间运行的任务,而又可以在多个任务之间添加依赖关系。可以跟踪进度,并且通过使用可以使调度变得容易OperationQueue。通过添加泛型和Swift结果类型,我们可以从异步操作中获得更多收益。

在开始操作并使用异步操作编写并发解决方案之后,现在该看看如何为我们的代码库提供更高级的解决方案。这完全基于我们在WeTransferCollect应用程序中使用的实现,其中我们使用了50多种不同的操作。

创建结果驱动的异步操作

通常情况下,某个运算会产生特定值。至少有一种捕获已发生的错误的方法很有价值。Result<Success, Failure>在Swift中,值和错误都归为一个类型。

将泛型添加到异步操作
通过利用AsyncOperation博客文章中创建的异步操作编写并发解决方案,我们为自己提供了一个起点。

class AsyncOperation: Operation {private let lockQueue = DispatchQueue(label: "com.swiftlee.asyncoperation", attributes: .concurrent)override var isAsynchronous: Bool {return true}private var _isExecuting: Bool = falseoverride private(set) var isExecuting: Bool {get {return lockQueue.sync { () -> Bool inreturn _isExecuting}}set {willChangeValue(forKey: "isExecuting")lockQueue.sync(flags: [.barrier]) {_isExecuting = newValue}didChangeValue(forKey: "isExecuting")}}private var _isFinished: Bool = falseoverride private(set) var isFinished: Bool {get {return lockQueue.sync { () -> Bool inreturn _isFinished}}set {willChangeValue(forKey: "isFinished")lockQueue.sync(flags: [.barrier]) {_isFinished = newValue}didChangeValue(forKey: "isFinished")}}override func start() {print("Starting")guard !isCancelled else {finish()return}isFinished = falseisExecuting = truemain()}override func main() {/// Use a dispatch after to mimic the scenario of a long-running task.DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(1), execute: {print("Executing")self.finish()})}func finish() {isExecuting = falseisFinished = true}
}

我们在其顶部添加与结果类型相同的泛型,从而得出以下基础:

class AsyncResultOperation<Success, Failure>: AsyncOperation where Failure: Error {private(set) var result: Result<Success, Failure>?}

这为异步任务提供了一个链接的结果类型,其值和错误均具有泛型。

确保完成结果

为了确保结果更新,我们在finish方法中添加了一个检查,以帮助实现者并在开发过程中向他们提供反馈:

final override func finish() {guard !isCancelled else { return super.finish() }fatalError("Make use of finish(with:) instead to ensure a result")
}func finish(with result: Result<Success, Failure>) {self.result = resultsuper.finish()
}

首先,我们确保默认finish()方法不再有用。当其实现者之一使用它时,它将引发致命异常:

致命错误:改用finish(with :)来确保结果:文件UnfurlURLOperation.swift,第44行

其次,我们添加了一个新finish(with:)方法,该方法强制实现者设置结果。

确保取消结果

最后一部分确保我们有一个关于取消的结果集。由于我们喜欢某种错误,因此我们不得不在类中创建另一个替代:

override func cancel() {fatalError("Make use of cancel(with:) instead to ensure a result")
}func cancel(with error: Failure) {self.result = .failure(error)super.cancel()
}

我们必须在错误枚举中定义一个案例以进行取消。这样做给我们带来了强类型错误的好处,同时在取消时仍然可以得到结果。

全部放到一个示例操作中

最终结果AsyncResultOperation如下所示:

open class AsyncResultOperation<Success, Failure>: AsyncOperation where Failure: Error {private(set) public var result: Result<Success, Failure>?final override public func finish() {guard !isCancelled else { return super.finish() }fatalError("Make use of finish(with:) instead to ensure a result")}public func finish(with result: Result<Success, Failure>) {self.result = resultsuper.finish()}override open func cancel() {fatalError("Make use of cancel(with:) instead to ensure a result")}public func cancel(with error: Failure) {self.result = .failure(error)super.cancel()}
}

我们可以通过创建自定义操作来使用此类,例如取消短URL的任务。

final class UnfurlURLOperation: AsyncResultOperation<URL, UnfurlURLOperation.Error> {enum Error: Swift.Error {case canceledcase missingRedirectURLcase underlying(error: Swift.Error)}private let shortURL: URLprivate var dataTask: URLSessionTask?init(shortURL: URL) {self.shortURL = shortURL}override func main() {var request = URLRequest(url: shortURL)request.httpMethod = "HEAD"dataTask = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (_, response, error) inif let error = error {self?.finish(with: .failure(Error.underlying(error: error)))return}guard let longURL = response?.url else {self?.finish(with: .failure(Error.missingRedirectURL))return}self?.finish(with: .success(longURL))})dataTask?.resume()}override func cancel() {dataTask?.cancel()cancel(with: .canceled)}
}

此类采用短URL,执行HEAD获取长URL的请求,然后将其返回。如果发生任何错误,则是由于操作导致的。最后,我们确保在取消时取消数据任务,并cancel(with:)使用canceled错误情况调用该方法。

执行此方法最终将导致www.avanderlee.com展开的URL:

let queue = OperationQueue()
let unfurlOperation = UnfurlURLOperation(shortURL: URL(string: "https://bit.ly/33UDb5L")!)
queue.addOperations([unfurlOperation], waitUntilFinished: true)
print("Operation finished with: \(unfurlOperation.result!)")// Prints: Operation finished with: success(https://www.avanderlee.com/)

结论

而已!我们通过在Swift中使用泛型来创建高级操作。通过将它们链接在一起,我们允许自己在任务之间建立关系,同时保持代码分离。

这篇文章是系列文章的一部分:

  1. Swift中的Operations和OperationQueues入门
  2. 在Swift中编写并发解决方案的异步操作
  3. 通过使用泛型进行高级异步操作

也可以以Swift Playground的形式找到:https://github.com/AvdLee/AsyncOperations

如果您想进一步提高Swift知识,请查看 Swift类别页面。

参考

https://www.avanderlee.com/swift/advanced-asynchronous-operations/

翻译:swift 5通过使用泛型进行高级异步操作Operation相关推荐

  1. Swift之深入解析“泛型”的底层原理

    一.泛型简介 ① Swift 泛型 Swift 提供了泛型可以写出灵活且可重用的函数和类型. Swift 标准库是通过泛型代码构建出来的,Swift 的数组和字典类型都是泛型集. 泛型可以创建一个 I ...

  2. java 高级泛型_java泛型的高级应用

    展开全部 在上面的例子中,由于没有限制class GenericsFoo类型持有者T的范围,实际上这里32313133353236313431303231363533e59b9ee7ad9431333 ...

  3. .net java 泛型_Java高级特性泛型看这一篇就够了

    作者:qwer1030274531 出自:ITPUB博客 1.为什么我们需要泛型? 通过两段代码就可以知道为什么需要泛型 /*** * 没有泛型的时候实现加法 */public class NonGe ...

  4. Swift 泛型教程入门

    原文:Swift Generics Tutorial: Getting Started 作者:Gemma Barlow 译者:kmyhy 更新说明:本教程由 Gemma Barlow 更新为 Swif ...

  5. Swift 泛型參数

    原文:http://www.cocoachina.com/newbie/basic/2014/0612/8802.html 本页内容包含:泛型形參语句和泛型实參语句 本节涉及泛型类型.泛型函数以及泛型 ...

  6. 商务翻译证,高级商务翻译证

    我们知道,商务英语翻译证是由中国商业联合会颁发的商务英语翻译证书,该证书是商务英语及相关专业人员上岗就业的依据,是工商.合资企业.外事单位用人的资格凭证,全国通用并网上注册.那么,如何考取商务翻译证, ...

  7. swift问题集--未完待续

    达到效果:理解并能口诉才能算过 Q:dynamic 的作用-红记 静态 动态 kvo kvc 继承NSObject 由于 swift 是一个静态语言, 所以没有 Objective-C 中的消息发送这 ...

  8. 33 个 2017 年必须了解的 iOS/swift 开源库第三方库

    本文翻译自Medium,原作者为 Paweł Białecki &lt;img src="https://pic3.zhimg.com/v2-c786777447261347b0d9 ...

  9. 4_常用类_集合_泛型

    JavaSE_第四周 包装类 基本类型 包装类类型(引用类型:默认值都是null) byte Byte short Short int Integer long Long float Float do ...

  10. swift java混合,如何在Swift中连接或合并数组?

    使用Swift 3,根据您的需求和品味,您可以选择其中一个 five following ways 来连接/合并两个数组 . 1.使用Swift标准库(: :)泛型运算符将两个数组合并为一个新数组 S ...

最新文章

  1. 盯紧那群养生的年轻人,他们的焦虑值300亿
  2. Swagger 注解~用于方法
  3. 删除git所有历史记录 仅保留当前文件
  4. Java集合框架之三:HashMap源码解析
  5. BZOJ2795/2890/3647 [Poi2012]A Horrible Poem 【字符串hash】
  6. hybris Models
  7. Codeforces 702B【二分】
  8. Windows下运行linux桌面程序
  9. 费尔个人防火墙采用两种封包过滤技术
  10. 89c52如何控制ad9833输出正弦波,三角波,方波。
  11. cad图纸问号怎么转换文字_CAD打开图纸后为什么文字显示为问号?怎么解决?
  12. talking web android,talking web(网页朗读插件) 免费版
  13. [matlab]三维画图
  14. 二胎政策来袭 职场妈妈生还是升
  15. 谷歌浏览器,查找CSS选择器
  16. ps cs6 64+32百度网盘分享
  17. Flask 框架设计模式
  18. 计算机用户名及密码修改,电脑用户名是什么意思(怎么修改及设置用户名)
  19. 20060525: Office 2007
  20. html5显示状态灯,如何使用css3+html5来制作文字霓虹灯效果

热门文章

  1. 程序员的离职小技巧之如何写出让接班同事无法维护的超级代码!建议收藏
  2. python中换行的转义字符_Python语言中表示换行的转义字符是____________。(2.5分)_学小易找答案...
  3. JS中使用MD5进行字符串加密
  4. oracle实施伙伴,甲骨文推出Oracle合作伙伴网络专属计划
  5. ××× L2TP over IPSec 配置
  6. Centos7下编译安装Nginx、Mysql、PHP(文章底部包含一键安装脚本)
  7. Spring 事务模型
  8. 三目运算符?:结合性
  9. expect实现自动通过堡垒机登陆
  10. 前端项目构建工具---Grunt