Tag: 异步

未来就在眼前– iOS和异步开发

在编程中,我们经常使用异步操作。 这可能包括诸如网络,文件系统,数据库,UI,长时间运行的任务或任何其他I / O事件之类的东西。 在iOS中,我们有许多机制可以处理此问题,包括GCD,NSOperation,NSNotifications,委托和回调。 期货是一种在iOS上不那么常见的结构,但已经很成熟,在其他语言(例如JavaScript和Scala)中更常见。 也称为诺言,延期,任务或异步; 该技术允许您以同步方式处理异步值,将连续传递样式的调用切换为直接样式。 通过使用期货,您的程序将更容易推理,因为不会有太多的嵌套调用。 但是未来到底是什么? 未来是对尚不可用的值的表示。 当您与未来合作时,您将不知道该值当前是否可用。 但是,您可以使用该值,就好像它可用一样。 价值一经获得,将来便会处理您的指示。 期货框架 如果您想在iOS应用中开始使用期货,则可以选择以下两种不同的第三方库: – BrightFutures – PromiseKit – FutureKit – 递延 – 螺栓 根据您选择的库,您将有不同的设计选择可以使用。 例如,Big Nerd Ranch的Deferred库的灵感来自OCaml的Deferreds。 这意味着将来/延迟值不会说明异步操作是否失败。 要表示失败,您需要通过返回Result类型或类似的关联枚举来将其表示为值的一部分。 BrightFutures遵循Scala的承诺和未来,因此有一个隐含的理解,即每个未来都可能失败。 FutureKit和Bolts还包含“已取消”状态,该状态表示用户何时取消了将来/任务并且不再关心结果。 这些库可能具有不同的方法和设计目标。 但是,它们都解决了提供一个接口来表示异步结果并使用异步结果的相同问题。 它们还处理共同的任务,例如一起对期货进行排序,并行运行期货以及在特定线程上处理结果。 因此,让我们深入。 只是基础 使用期货的最基本方法是设置完成处理程序。 只要值可用,就可以简单地执行操作。 要设置处理程序,您可以在将来通过调用onSuccess (BrightFutures / FutureKit), 在 (Deferred), 然后 (PromiseKit)或continueOnSuccessWith (Bolts)来设置延续功能。 这些框架中的大多数还允许您通过调用onFailure (BrightFutures), onError (FutureKit)或catch (PromiseKit)来附加错误处理程序。 […]

Swift中更好的承诺

一个简单的承诺 异步代码很常见,但是如果我们仅在一个地方添加更多的异步调用,我们将得到大量的方法和十个级别的缩进。 换句话说,我们将成功实现回调地狱。 当然,我们可以做得更好! 我们可以尝试将其拆分为几个功能……但这可能会导致其他问题…… 这种方法的缺点是很难跟踪控制流。 从方法签名来看,不清楚哪个方法被调用。 如果方法调用是实现方法职责的一部分,那么这是一件好事,但是如果它调用了流程管道中的下一个项目,那么它很快就会变成可控流地狱。 这就是为什么我们首先要有回调! 我们希望在一个地方定义高级控制流,然后将实现细节放在其他地方,并适当地封装它们。 一种可能的解决方案是使用诺言。 那么, 什么是诺言? 承诺(也称为“未来”)是指用于同步程序执行的构造。 他们描述了一个对象,该对象充当最初未知的结果的代理 ,通常是因为其值的计算尚未完成[1]。 我为什么要使用诺言? 保持代码干净和结构良好。 这是避免回调地狱和控制流地狱之类的简单选择。 我们始终希望代码缩进尽可能合理 ,而诺言是实现这一目标的好方法。 答应过地狱? 根据使用方式的不同,promise可以简化代码,但也会使代码难以理解。 在进行代码审查时,我基本上遇到了一件奇妙的事情: 相当多的工作,不是吗? 乍一看,这是有问题的,因为代码在美学上看起来并不令人满意(在我看来,这是判断代码质量的很好指标)。 不幸的是,使用promise退化为类似代码的代码并不少见。 所以有什么问题? 很难说出.then块的作用,它们可能变得非常庞大。 它也违反了单一责任原则[2],因为每个块都有单独的责任,但是它们都包含在一个方法中。 我们遇到的另一个问题是缺乏抽象层的分离。 一个方法应该只包含占据一个抽象层的代码,在我们的例子中,我们可以说有两个:1.管理过程流程的代码,以及2.构成过程步骤的实现细节。 更好的承诺 一种简单的解决方案是在每个块的开头添加注释,以描述其功能。 更好的解决方案是编写自我记录代码 ,在这种情况下,这意味着将程序包提取到单独的方法中 。 只要确保正确命名方法即可 。 而且您还需要正确命名方法(我已经说了两次,因为它很重要,以防您想知道)。 最初的问题是,我们无法轻易分辨出发生了什么,而用模糊的内容代替它并不会带来太大帮助,对吗? 即使块的内容包含很多代码,如果将其包含在方法中,它也更易于管理,并且我们还解决了抽象层问题。 答应天堂? 由于Swift函数是一流的对象,因此我们可以采取进一步的措施。 这意味着我们可以将它们传递到其他需要关闭的函数中 。 promisseHell示例将变为以下内容: 我们可以选择几种承诺库。 最受欢迎的可能是PromiseKit [3]。 就我个人而言,我更喜欢then框架[4],因为它的方法不需要标签,这使它更加简洁(即在那时我们将编写.then (handler),而在PromiseKit中将是.then (execute:handler) )。 任一种都可以,但是您将需要根据所选框架的期望编写略有不同的代码。 […]

RxSwift:Swift中的反应式编程

RxSwift是iOS的反应式编程库。 它使对响应应用程序中的数据更改和用户事件的动态应用程序进行编程变得容易。 为什么使用它: 多平台 简化多线程 可比较的组件。 清洁代码与架构 因为您可以用一种优雅的方式处理异步问题。 因为您可以编写更好,更简洁的代码,并创建可以在健壮的代码库中重用的组件,所以这些代码库可以不断发展。 缺点: 一开始,学习过程可能会令人生畏–没有一篇文章可以教您RxSwift 内存管理问题-如果您不小心闭包内部的自引用,很容易造成内存泄漏 考虑到堆栈跟踪要大得多,调试可能很难 最后的话: 选择应用程序的隔离部分,然后将其迁移到反应式 支持MVVM和MVC的最佳架构 为什么要使用RxSwift? : 因为您可以用一种优雅的方式处理异步问题。 因为您可以编写更好,更简洁的代码,并创建可以在健壮的代码库中重用的组件,所以这些代码库可以不断发展。 您应该一直使用它吗? 作为任何工具,如果适合,则应使用它。 考虑您的团队知识,背景,时间表,并尝试做出有根据的决定。 从长远来看,我认为值得付出努力。 阅读更多:https://medium.com/@leandromperez/why-use-rxswift-a176b553a705 建议〜慢点RxSwift : 将RxSwift应用于项目时,不要全力以赴。 选择应用程序的隔离部分,将其迁移到响应式,然后权衡此新方法的优点,区别,优点和缺点。 阅读更多:https://techbeacon.com/reactive-programming-rxswift-how-get-started

将iOS和Mac异步和相关任务封装到Cocoa Operation子类中

异步任务(例如,从网络中获取数据,解析,处理数据并将数据保存到本地缓存中)是当今应用程序执行的常规任务。 作为开发人员,我们必须确保UI /主线程运行平稳,并将长时间运行的繁重工作任务移入后台线程,以维持60 FPS动画。 Apple为开发人员提供了两种在后台线程中执行任务的方式: 大中央调度(GCD):开发人员可以使用队列在后台线程池中串行或并发执行任务的API集。 操作(也称为NSOperation):可可抽象类,代表要执行的单个任务单元。 它是一个线程安全类,具有开箱即用的内置状态,优先级和QoS,取消和依赖项管理。 在本文中,我们将构建一个异步的Operation子类,该子类可从GitHub API异步获取存储库,以及一个从属的Operation子类,可将获取的存储库数据解析并将其序列化为Swift类。 我们将建立什么 AsynchronousOperation:支持异步操作的Operation子类。 FetchRepoOperation:AsynchronousOperation子类,该类从上周开始使用URLSession异步获取最新趋势的GitHub存储库的数据。 ParseRepoDataOperation:操作子类,该子类使用Swift Codable和JSONDecoder将FetchRepoOperation中的数据解码并序列化为GithubRepo对象的数组。 游乐场页面:使用OperationQueue执行操作,在操作之间添加依赖关系,并使用完成块在操作对象之间传递数据。 使用Operation子类实现异步操作 默认情况下,Operation Class同步运行代码。 Apple提供了一种通过子类化isAsynchronous布尔属性并将其重写为true来异步运行代码的方法。 我们还需要使用枚举添加我们自己的状态管理属性,处理从就绪,执行和完成状态的更改。 当同时读写状态属性时,dispacth队列将用于对状态属性使用调度屏障来处理同步。 在启动函数中,我们检查任务是否未取消,如果取消,则仅调用finish将状态更改为完成并返回。 如果没有,我们将状态设置为执行并调用主函数。 我们的子类将覆盖main函数,以执行函数内部的任务。 实现FetchRepoOperation来获取Github API FetchRepoOperation是异步操作的子类,我们声明两个可选属性,fetchedData是一个Data对象,将用于存储来自API调用的数据响应,以及一个error属性,将用于存储来自API的错误如果发生,请致电。 在超类的重写的main方法中,我们构造URL和查询项,这些查询项将查询自上周以来创建的存储库,该存储库按星数降序排列。 之后,我们初始化URLRequest并使用URLSession调用异步数据任务。 在数据任务完成处理程序内部,我们将响应数据和错误分配给实例属性,然后调用finish方法将操作的状态设置为finish,以将操作标记为完成。 实施ParseRepoOperation以使用Swift Codable类解码JSON数据 我们创建GithubRepoFetchResult,GithubRepo,GithubOwner Swift类,该类实现了codable和CodingKeys枚举,以将json属性名称映射到实例属性骆驼案例名称。 通过使用Codable,我们可以利用JSONDecoder将Data解码为自动实现Codable的类。 实现ParseRepoOperation非常简单,我们将Operation用作子类,因为JSONDecoder的解码功能是同步的,因此我们不需要使用AsynchronousOperation。 我们声明了3个可选的实例属性,fetchedData是从FetchRepoOperation传递的数据,如果将数据解码为对象时发生错误,则错误为Error对象,包含GitHubRepo的repos数组将用于将JSONDecoding的结果存储到对象中。 在main函数内部,我们使用guard来解包可选的fetchedData,如果为nil,我们只是从函数中返回。 之后,在try catch块中,我们使用JSONDecoder解码函数,将fetchedData和GithubRepoFetchResult作为要解码的根类。 然后,我们将GithubRepoFetchResult中的items属性分配给repos实例属性。 如果解码时发生错误,我们会将错误分配给我们的错误实例属性。 使用OperationQueue执行操作 为了执行操作,我们使用OperationQueue,它充当优先队列,该队列使用先进先出机制来处理操作的执行。 我们将maxConcurrentOperationCount设置为1,因此我们的操作不会同时执行。 我们实例化FetchRepoOperation和ParseRepoOperation对象,然后将FetchRepoOperation对象添加为ParseRepoOperation对象的依赖项,因此将首先启动fetch任务,并且必须完成分析任务才能开始。 在操作之间传递数据并不容易,有许多方法可以做到,例如使用包含数据的数据包装器引用类,然后将其传递给每个操作。 对于此实现,我们将使用操作完成块,该操作将在操作完成时调用。 我们参考解析和提取操作对象为提取操作完成块分配一个闭包。 使用Unowned来避免保留周期,在该块内部,我们将获取响应数据传递给了解析的fetchedData属性。 我们为解析操作完成块属性分配一个闭包,该闭包仅循环存储库并将打印库的名称打印到控制台,以便我们看到结果。 最后,要开始操作,我们将调用包含获取和解析操作的数组传递给OperationQueue的addOperations来开始任务。 结论 可可操作类为开发人员提供了极大的灵活性,例如任务之间的依赖性,调整队列优先级和QoS,执行后台任务时的取消和状态管理。 […]

适用于iOS的同步网络方法

这篇文章提出了一种同步处理网络的方法。 它开始回顾当今如何异步处理网络,继续检测异步性的源头,并以展示如何删除它如何改善可伸缩性,可测试性,表达性,模块化和线程控制为结尾。 如今联网 当作为移动开发人员,我们需要从服务器获取数据并将其显示在设备中时,我们遵循的方法不会冻结UI: 我们在主线程中显示了一个动画微调器; 我们在另一个线程中请求数据; 当请求完成时,我们返回主线程; 我们删除了微调器; 我们使用接收到的数据刷新UI。 我们获取和呈现数据而不冻结UI的方法。 数据来自以下服务: 使用NSURLSession,Alamofire或其他机制发送HTTP请求; 使用本机工具,SwiftyJSON或其他库解析HTTP响应; 将结果(事物数组或错误)统一为两个可选参数或结果monad; 使用回调机制,作为参数接收的函数或先前分配的委托返回结果。 一种可能的服务实现,它使用回调来返回获取的数据(或错误)。 异步的根源 从网络获取数据的任何组件都必须异步处理,以避免冻结应用程序; 但是,应该在API级别包括异步性吗? 我们以后不能处理吗? API级别的异步性迫使我们立即对其进行处理; 我们无法决定何时处理。 如果我们注意前面的代码段,则在发送HTTP请求时会出现异步性。 我们丢失了流控制,并在调用作为参数传递的函数时将其恢复。 然后,如果我们在另一个线程上,则返回主线程以更新UI。 吻:保持同步,s **** d! 让我们删除异步源,以异步方式转换异步服务API: 自iOS 9以来,没有很多库向我们提供同步请求,并且不赞成使用本机执行同步请求的方法,但是我们可以使用本机SDK解决该问题。 首先,它看起来非常简单:您想要的东西,可以调用getThings() ,您将收到您想要的东西(或错误)作为返回值。 但是,如果您在主线程中调用它,则该应用程序将冻结,直到我们收到对HTTP请求的响应。 因此,现在该处理它了: 我们使用此辅助函数来提高可读性和模块化性,但是我们可以直接使用SDK,使用任何async-await库,任何Futures库或继续期待Swift 5。 这样,我们选择在后台线程中执行服务以避免冻结应用程序。 一些优点是: 该代码更简单,语义上也更好。 我们索要一些东西,然后得到它作为……一个返回值☺,而不是作为回调函数或委托方法中的参数(参数用于发送事物,而不是返回它们)。 我们在控制线程。 我们决定在后台线程中以有效意图执行某些代码(不阻塞UI),我们决定以另一个明确定义的目的返回主线程(更新UI)。 如果不需要,我们不在乎切换线程。 我们可以通过一种更简单的方式伪造服务,无需在延迟后调用回调,只需将所需的值作为返回值返回即可。 我们可以以更舒适的方式测试服务,无需期望,因为在运行测试时没有UI线程会阻塞,因此您可以在当前线程中同步使用服务。 重要的是要注意,这些测试是集成测试,而不是单元测试。 使用服务时,我们是在测试环境(在最佳情况下为此类测试专用的环境)中创建/修改/删除实体。 我们可以以可扩展的方式编写服务呼叫。 一些缺点是: 以非标准方式处理网络。 没有同步发送网络请求的直接方法。 结论 软件组件的API定义了其使用方式。 如果我们在组件内部处理异步性,并添加回调函数作为参数,那么我们将迫使使用API​​的任何人立即处理异步性。 […]

使用Promise模式在Swift中编写更干净的异步代码

在Swift 4中编写异步代码的当前状态是什么? 当前最常用的模式是提供一个回调闭合,当任务完成传递结果或错误时将调用该闭合。 尽管此模式有效,但是当我们需要编写多个异步任务时(这也取决于先前任务的结果),很难维护和理解它。 异步函数相互嵌套在一起,在我们的代码中可能会导致“厄运金字塔”。 计算机科学家发现的解决此类问题的方法之一是使用Promise模式,该模式被广泛用于编写现代ES6 Javascript应用程序。 什么是承诺? 简而言之,promise是一个对象,代表异步任务的最终完成(或失败)。 操作的完成状态可以为未决,失败和完成: 待处理:任务尚未解决,任务尚未完成。 已完成:具有价值结果的已解决任务 拒绝:已解决任务,但有错误。 许诺对象完成或失败时的状态是最终状态,永远不会改变。 许诺对象可以附加到许多观察者,当许诺完成其任务(提供值的结果)或当许诺失败(使用错误对象提供错误原因)时,可以通知这些观察者。 完成后,promise的观察者将返回另一个promise对象,或者他们可以返回void以结束订阅。 当它返回另一个promise对象时,它可以用于执行异步任务转换的多个链接管道,以转换每个promise的值。 Promises的其他主要功能: 并行执行多个异步任务,并在所有任务成功完成时解决。 执行许多异步任务的竞赛,并使用其值解决首先完成的任务。 对promise的错误处理也非常简单,只有一个简单的catch错误处理程序可以捕获所有promise管道操作。 查看上面的源代码,我们可以看到,使用Promise链接模式和单个错误捕获处理(如果任何promise失败),可使代码看起来更简单易维护。 我们可以使用许多Cocoapods库将Promise集成到我们的iOS应用程序中。 我最喜欢的之一是Google编写的Promises库,它是用Objective-C编写的,并且与Swift完全兼容。 与其他PromiseKit等Promise库相比,该库的性能也相对较快,并且二进制大小更轻巧。 只需将此行添加到您的Podfile中即可进行集成: pod’PromisesSwift’ Google Promises库的主要功能取自其GitHub存储库: 简单:该框架具有直观的API,这些API的文档齐全,可轻松集成到新代码或现有代码中。 互操作性:支持Objective-C和Swift。 在Objective-C中创建的承诺可以在Swift中使用,反之亦然。 轻量级:具有最小的开销,可以达到与GCD和完成处理程序类似的性能。 灵活:可以在任何线程或自定义队列上调度观察者块。 安全:GCD捕获了所有的诺言和观察者阻止,这有助于避免潜在的保留周期。 已测试:该框架具有100%的测试覆盖率。 谷歌/承诺 Promises是一个现代框架,为Swift和Objective-C提供了同步结构。 – google / promises github.com 我们创建一个接受ClosedRange Int作为参数的函数,然后输出一个Promise对象,该对象通过执行参数中传递的数字范围的总和来解析为整数值。 要创建Promise对象,我们只需使用Promise初始化程序,它是一个通用的初始化程序。 我们使用Int作为返回值,然后告诉初始化程序在全局调度后台队列内执行执行。 我们将一个闭包传递给包含要执行的任务的初始化程序,该闭包提供2个参数,complement和reject。 我们使用实现来解决带有值的承诺,而使用拒绝来解决带有错误的承诺。 我们调用传递范围在1到100之间(包括1和100)的数字范围的函数,以生成Promise对象,我们可以通过使用then关键字来传递观察值,该关键字传递在promise解析结果以打印结果时将调用的闭包。 如果您要链接另一个Promise,也可以在完成闭包中返回另一个Promise对象,在这种情况下,由于我们不返回任何Promise对象,因此Promise链已结束。 在这里,我们创建一个返回Promise的函数,在promise任务闭包内,我们只是拒绝传递生成的NSError对象的任务。 我们调用该函数以生成Promise,然后对其进行观察。 底部的catch关键字将始终捕获Promise链中的错误。 在此示例中,我们将创建2个Promise: […]

在Swift中同步异步

我确定您已经遇到过异步任务,并且必须使它们同步执行的情况,因为它们之间存在依赖关系。 想象一下安排会议的场景 调用一些登录API以获得令牌 获取特定时间的可用人员列表 得到一个人的细节 与有空人员开会 在您大声疾呼这只是API的不良示例之前,请放心,我同意您的观点。 但这是我们现实太多次了。 但是,有一个开箱即用的解决方案: 在队列上 使用 操作 和链接相关任务! 这听起来像是我们要实现的教科书示例。 让我们使用操作并使其起作用: 我们可以看到我们有一个Operation SumOfTwoAsyncOperations 。 我们可以清楚地看到它的业务逻辑在全局后线程队列上的异步调用中执行业务逻辑。 这里我们有一个函数sumOfTwoAsyncOperations ,它接受4个数字,并在operation1添加number1和number2在operation1添加number3和number4 。 我们可以看到,我们还创建了BlankOperation类型的“虚拟” operation3 BlankOperation ,其唯一目的是确认最后执行的操作,该operation3应为operation3并将消息打印到控制台中。 因此,如果现在调用此函数: 使用参数4和5,那么我们期望在控制台中获得以下输出: 运算1之和4 + 4 = 8 运算2总和5 + 5 = 10 操作2完成! 好吧..不! 我们得到这个: 操作2完成! 运算2总和5 + 5 = 10 运算1之和4 + 4 = 8 我们得到相反的顺序,但是即使那样也不能保证。 实际上,我们无法真正控制结果。 如果我们还记得本文中的讨论,则提到了依赖性管理,而其他一些操作并非完全免费或完全免费。 […]

iOS开发课程:调度

如何并发执行代码? 如何管理调度工作单位? 让我们在快速指南中使用Dispatch框架创建一个简单的项目! 调度包括语言功能,运行时库和系统增强功能,这些系统功能全面,全面地改进了对macOS,iOS,watchOS和tvOS中多核硬件上的并发代码执行的支持。 BSD子系统,Core Foundation和Cocoa API均已扩展为使用这些增强功能,以帮助系统和您的应用程序更快,更高效地运行,并提高响应速度。 考虑单个应用程序有效地使用多个内核有多么困难,更不用说在具有不同数量计算内核的不同计算机上或在多个应用程序竞争那些内核的环境中进行操作了。 在系统级别运行的GCD可以更好地满足所有正在运行的应用程序的需求,并以平衡的方式将它们与可用的系统资源进行匹配。 阅读有关Apple Developer的更多信息 每个工作项都可以同步或异步执行。 当工作项与sync方法同步执行时,程序将等到执行完成后再返回方法调用。 当使用async方法异步执行工作项时,该方法调用立即返回。 通过同步 / 异步执行在操场上运行以下代码 分派队列可以是串行的 ,以便一次执行一个工作项,也可以是并发的 ,以使工作项按顺序出队,但可以一次全部运行并且可以按任何顺序完成。 串行队列和并发队列均以先进先出(FIFO)顺序处理工作项。 在操场上修改代码,然后再次运行。 现在我们有一个并发队列。 *默认为串行 启动应用程序时,系统会自动创建一个称为main queue的特殊队列 。 排队到主队列中的工作项在应用程序的主线程上顺序执行。 您可以使用main type属性访问主队列。 重要 尝试在主队列上同步执行工作项会导致死锁。 在操场上运行代码。 那演示了如何从background在主队列上执行代码。 除了串行主队列之外,系统还创建了许多全局并发调度队列。 您可以使用global(attributes :)类型方法访问与指定服务质量(QoS)最匹配的全局并发队列。 该代码演示了使用不同qos模式的队列初始化。 工作项使您可以直接配置各个工作单元的属性。 它们还使您可以为各个工作单元着想,以等待其完成,收到有关其完成的通知和/或取消它们的目的。 DispatchWorkItem封装了可以执行的工作。 可以将工作项分派到DispatchQueue和DispatchGroup 。 也可以将DispatchSource设置为DispatchSource事件,注册或取消处理程序。 使用WorkItem管理演示程序在操场上运行代码。 分组块允许聚合同步。 您的应用程序可以提交多个块并跟踪它们何时完成,即使它们可能在不同的队列上运行也是如此。 如果在完成所有指定任务之前无法取得进展,此行为将很有帮助。 DispatchGroup允许工作的聚合同步。 您可以使用它们来提交多个不同的工作项,并跟踪它们的完成时间,即使它们可能在不同的队列中运行。 如果在完成所有指定任务之前无法取得进展,此行为将很有帮助。 你完成了! 拍! 拍! 接下来是什么? […]

在Swift中同步多个异步任务

您可能会遇到这样的情况:首先需要完成一些异步任务,然后才能跳到快速程序的下一个阶段。 在本文中,我们研究了可以应用于异步运行任务并在流程结束时获得通知或获取结果的不同解决方案。 通常,您可能需要先存储多个网络请求的结果,然后再向用户显示正确的数据。 的确,如果您必须请求许多网络资源来执行应用程序的功能,它可能会消耗更多的设备能量,您可能会三思而后行,但这与本文无关。 假设我们有一个示例网络请求函数,如下所示: 我们希望通过网络满足一些网络要求: 在上面的示例中, baseUrl指示我们的基本端点URL,并且这些endpoints是来自Web服务器的不同请求。 多个独立任务(并发队列) 我们可以有彼此独立的不同异步任务。 这意味着我们可以以任何顺序运行它们,并且一个结果与另一任务无关。 派遣组 Grand Central Dispatch或GCD自动管理线程的创建,并根据iOS中可用的设备资源来平衡线程的创建。 我们可以使用DispatchGroup创建一堆异步任务,并在所有任务完成后继续我们的工作: 当任务完成时,我们已通知主线程,但也可以是其他任何线程。 以下输出可能是结果(或子任务完成的任何任意顺序): 任务相册已完成 任务发布完成 待办事项 任务注释已完成 任务用户完成 任务照片完成 所有任务都完成了 如您所见,在处理完所有任务后,我们收到了“所有任务已完成”消息。 承诺 强烈建议您使用一种模式来解决此问题:承诺。 一般来说,promise表示异步任务的最终结果 ,或者表示任务失败时的错误原因 。 类似的概念也称为期货 (有关更多信息,期货和承诺,请参阅此Wiki文章)。 我们可以假设一个承诺的3个不同状态: 待处理 :尚未解决的任务,结果尚不可用 已完成 :具有一定价值的已解决任务(成功响应) 拒绝 :已解决任务,但有错误 有很多Cocoapods库可以提供承诺。 Google Promises是Swift中最好的实现之一: 谷歌/承诺 Promises是一个现代框架,为Swift和Objective-C提供了同步结构。 – google / promises github.com 现在我们可以使用Promises更新解决方案: 可以看出,promise简化了异步任务过程。 在performNetworkPromise我们首先创建了一个待处理流程,该流程将返回一些数据。 就像我们已初始化的一个空的异步请求容器一样。 承诺中的数据类型决定了将要满足的数据类型。 […]

承诺:一种使异步网络代码“ NSYNC”的方法

有了一个承诺,我就不需要在完成闭包中处理字典的解析,我可以将该动作链接到“获取JSON数据”动作。 见下文: 在上面的代码要点中,在第1行上,您可以看到我的getArticles()方法返回了Promise 。 此功能“有前途”的意思是,在我收到文章后,我将返回文章的承诺。 我将通过返回文章(也就是我在第13行的结果 )来实现这一承诺。 为了实现这些承诺,我使用了一个名为PromiseKit的第三方库。 我将向您介绍如何将PromiseKit集成到我的应用程序中。 首先 -为您的项目创建/打开一个Podfile。 在Terminal中,我使用Sublime(因此称为subl Podfile)打开了Podfile。 确保您位于项目文件的当前目录(文件夹)中。 第二个 -在您的Podfile中,在下面添加第10行。 保存并关闭此Podfile。 第三 —在终端中,键入“ pod install”。此说明将PromiseKit库安装到您的项目中。 第四 -在终端中,打开.xcworkspace (而不是.xcodeproj)! 第五步–在要编写网络代码的文件中,在顶部导入PromiseKit。 按⌘+ B,这会将PromiseKit库构建到您的项目中。 第六 -开始编写代码! 在这个应用程序示例中,我有一个Article模型(上文),它将从NYTimes API获取数据以创建Article对象。 我已经在上面的屏幕截图中注释了我的代码,但是我将在这里再次概述它: A —我没有使用完成闭包,而是让我的网络函数返回了类型为Promise的Promise。 B — Promise块需要实现和拒绝方法。 C-这个URL是我用来获取任何Cuba文章的NYTimes API数据的URL。 古巴是我去过的最有趣的国家。 (旁问:您访问过的最有趣的国家/地区是什么?) D-解开网址后,创建一个URLRequest E-创建一个URLSession F —创建一个URLDataPromise(PromiseKit随附)。 它返回一个专门的Promise包装URLSession.dataTask(with :)。 重要的是要注意,这是我们要做的第一个动作,第一个承诺。 我们正在写一个从dataPromise获取数据的承诺。 G —在我的dataPromise上,我做第二个PROMISE。 我们承诺将数据(从我们的第一个承诺开始)转换为反序列化字典。 您会注意到.then语法。 读起来很不错,就像您说的那样:“如果出现此内容,那么我会做些处理。” H-现在第二个承诺已经实现(我有一个字典),我可以使用该字典创建我的Article对象之一。 […]