使用闭包接收异步操作的结果 接收异步操作的结果已经很久了。 在iOS上,它以Delegate,Notification开始。 自从引入Objective-C的代码块以来,它已经演变为使用Swift的Closure。 特别地,闭包是功能编码的核心。 由于它的紧凑表示形式和基于编译器强大推断能力的各种简短公式,它也几乎用于Swift编码的各个方面。 使用Closure处理工作的结果有多种方法。 您可以考虑处理用户操作的结果,例如处理UI事件或处理警报选择结果。 此外,它可以在通过GCD执行异步操作后接收结果,也可以用于通过网络接收数据时的处理。 让我们考虑一下使用Closure调用Restful API之后接收结果的过程。 基本上,您需要一个闭包以在调用成功时接收结果,并需要一个闭包以在失败时接收错误。 您必须将两个闭包对象作为参数传递给调用Restful API的方法。 func getUserProfile(userId:Int,complete:(((JSON)-> Void),failure:((Error)-> Void)){ //成功调用成功,失败调用失败 } 这是最简单的思考方式。 然而,这种类型的封闭物递送和结果接收存在缺点。 上面调用getUserProfile函数的语法如下所示。 getUserProfile(userId:123,complete:{json in //成功动作 },失败:{error in //失败动作 }) 如果要将另一个状态的处理程序添加到getUserProfile,则不方便更改所有其他调用此方法的部分。 另外,如果将多个闭包作为方法参数传递,则不容易理解方法本身的签名,并且阅读起来也不那么好。 应用Promise语法 考虑一下JavaScript的承诺。 处理JS异步操作结果的传统方法是将Callback函数作为参数传递给工作函数。 但是,JS应用程序变得更加复杂,回调函数也变得更大。 同样,如果必须连续执行异步处理,则必须嵌套多个回调函数。 因此,它导致了代码难以阅读的问题。 解决这个问题的承诺已经出现。 可以将Promise对象传递给Task并为其添加一个Handler,而不是将Callback函数作为参数传递给work函数。 结果,诸如处理结果或执行另一任务的代码可以被添加为链。 这种方法解决了回调函数的缺点。 somePromise(task).then((result)=> { //做其他任务 })。then((result)=> { //结果处理 }) 通过上述链结构,一个函数只能包含与一项任务相关的代码,并且可以解决回调函数的嵌套问题。 在iOS开发中,闭包对象很少嵌套。 但是,在iOS中,如前面的示例中所述,类似的是,当将闭包作为函数的参数传递时,函数调用语法很复杂,并且很难修改签名。 因此,让我们创建一个类似于JavaScript的Promise对象,以改进用于异步处理的代码,并使用它来调用Restful API。 换句话说,我想向您展示如何通过以下语法使用getUserProfile。 […]
闭包คือ功能ที่ไม่ต้องประกาศชื่อ功能ไม่ต้องมี关键字Funcนำหน้า……..เพื่อนๆอาจเกิดคำถามว่าเพื่ออะไร? Functionาๆงั้นเรามาดูต่อกันว่าไอเจ้า功能พิลิกกึกกือแบบนี้เราจะใช้มันในสถานการณ์แบบไหนได้บ้าง 闭包จะใช้ในกรณีที่เราอยากส่ง函数ไปเป็น参数ของอีกFunctionหรือให้函数。 Returnาร返回函数ออกมา…ยิ่งพูดยิ่งงงมาลองดูตัวอย่างกันดีกว่า 复仇者联盟3英雄级别英雄级别英雄级别英雄级别 英雄级{ 在里面() { 打印(“我是英雄”) } funcpunch() { 打印(“我可以打孔”) } funk kick() { 打印(“我可以踢”) } } งใช้องใช้Heroของเรากันดู let ironMan = Hero()//我是英雄 ironMan.punch()//我可以打孔 ironMan.kick()//我可以踢 จะให้ราวนี้เราจะให้Heroของเราสามารถเรนยนรู้สกิลใหม่ๆมาใช้งานได้เช่นน,ยิงจรวด,ยิงเลเซอร์,หายตัว,เปิดเกราะกำบัง…。 สกิลอีกมากมายนับร้อยสกิล………..อืม…มีสกิลมากมาย….. าเป็น绿巨人ก็ไม่จำเป็นต้องบินได้แปลว่าในแต่ละHero。 ังไงดีกักักักักัๆกแบบคลๆ งาลองทำกันเริ่มจากสร้าง关闭技能ต่างๆไว้ดังนี้ var fly:()->()= {()in print(“ i can fly”)} var fireRocket:()->()= {()in print(“ Locktarget-> Fire the rocker-> Boom!”)} เพิ่ม功能使用技巧ใน类英雄ของเรา 英雄级{ 在里面() { 打印(“我是英雄”) } funcpunch() […]
尊敬的开发商, 欢迎使用,今天我们将研究什么是闭包捕获列表以及如何快速使用它。 例子1 如果您曾经看过上面的代码,并且想知道[]之间的hack是什么,或者您无法理解,则可能是数组之类的东西。 这只是关闭捕获的列表。 不要强调[弱者],一旦完成本教程,您将能够解决这个谜团 让我们从一个简单的例子开始 例子2 闭包打印不同的值,因为闭包引用了变量“ a”和“ b”。 是闭包是引用类型,当值更改时闭包将反映出来。 有时,如果您的变量发生更改并且闭包引用了该变量,那将是非常灾难。 让我们通过示例来了解这个问题。 例子3 在上面的示例中,我们创建了一个闭包数组。 闭包不带任何参数,也不返回任何东西。 接下来,我们向闭包数组{print(i)}添加一个值 我们何时迭代并像这样调用闭包。 您能猜出输出是什么吗?……,嗯,如果您认为输出将是1 2 3 4 5,那么这里就不是这样了。 输出将是 所以这里出了什么问题,孔闭合是在执行for循环后引用i的最终值, 即 5 解决方案:让我们回到我们的第一个Example 2类型。 上面的闭包与示例2相同,但是差异[c,d]很小,您可能将其与数组混淆。 让我解释一下,当您在[ in ]之前的[]中输入变量时,闭包不再引用原始值,而是创建自己的变量副本,这称为C aptured list。 因此,即使您更改了原始值,闭包也不会反映该更改。 因此, 示例3的解决方案是 现在每个闭包捕获每个循环中j的当前值,因此当我们迭代数组时,输出将为0 1 2 3 4。 有时我们可能想为捕获的变量使用不同的名称,我们也可以像上面的示例一样更改。 在上面的示例中,我们采用了一个新的变量“ capturedJ”,好像我们不想知道原始值来自何处。 消息:我没有在本教程中介绍什么是“弱自我”,因为我将以“带有闭包的内存管理”的形式对此进行介绍。
在本文中,我们将探索Swift的一个非常简单但非常有趣且有用的功能,称为Autoclosures。 如果您不熟悉此概念,那么前几个问题可能是:那是什么? 和“正常”关闭有什么不同? 好吧,让我们从Swift.org语言指南中的定义开始 自动闭包是一种自动创建的闭包,用于包装将作为参数传递给函数的表达式。 它不带任何参数,并且在调用它时,它返回包装在其中的表达式的值。 这种语法上的便利性使您可以通过编写正则表达式而不是显式闭包来省略函数参数的花括号。 所以……基本上,自动闭包是封装表达式并返回该表达式的结果值的闭包。 如果您定义一个以自动闭包为参数的函数,例如,定义一个函数func f(_ x:@autoclosure()-> Int),则基本上可以使用与普通函数相同的语法调用该函数。像f(3)这样的Int类型,编译器确保将其包装在闭包内。 因此,对于调用方而言,它变化不大。 但是自动关闭的最大优点是它们使我们可以延迟表达式求值,因为该表达式仅在函数调用关闭之后才运行。 表达式的计算成本很高并且不能在函数内部使用时,可以很好地使用它。 说了这么多,让我们来看一个代码示例 这就是本文的全部,希望您喜欢🙂 如果您有任何意见或疑问,请告诉我。 我很高兴收到您的反馈feedback 您可以在Twitter上@ LucianoPassos11找到我。 感谢您阅读🙂 参考文献 Swift编程语言(Swift 4.2):语言指南:闭包。 https://docs.swift.org/swift-book/LanguageGuide/Closures.html
以前,我们了解了代码结构,可读性和其他一些原理。 Swift编程入门第10部分-代码结构,可读性和原理 在上一篇文章中,我们介绍了基本协议,扩展和下标。 medium.com 是的,它不是技术性很强的工具,但是如果您一直在磨练自己的技能,那么您的项目就会变得相当庞大,并且您可能已经开始考虑可以使代码井井有条的方式。 项目之间的代码结构各不相同,因为在开始首次工作编程之前,开发人员很少谈论如何布局代码。 即使那样,它大部分时间还是安静的,只是希望您能赶上。 如果您尝试自己编写应用程序,则这样做的效果不太好。 当我们讨论了可读性时,我几乎不讨论任何事情,但是我为您提供了基础知识,因此当您回到代码中时,就不会迷失方向。 我可以只写一篇关于代码结构或可读性的整篇文章,但是为了使事情快速发展,我略过了。 如果您想了解有关结构或可读性的更多信息,请告诉我,本系列结束后,我将计划一些深入的文章。 最后,我们介绍了一些原则以为您提供指导,以及更多有关我为何以这种方式编写代码的上下文。 让我们开始吧。 Grand Central Dispatch是Apple处理称为调度队列的方法。 队列有三种类型: 串行 -按接收顺序执行发送到队列的工作,先入先出(FIFO)。 这些也称为专用调度队列。 并发 – 同时执行发送到队列的工作。 每个任务的启动顺序与将它们添加到队列的顺序相同。 串行队列和并发队列之间的主要区别在于,在串行队列中,下一个任务要等到第一个任务结束后才开始。在并发队列中,下一个任务可能不需要与第一个任务一样多的时间来完成,并且可能在第一个任务之前完成第一个任务完成。 在决定使用哪个队列时,请记住这一点。 这些也称为全局调度队列。 主调度队列 -这是应用程序的主线程,或应用程序所在的位置。 当您将代码放入View Controller的viewDidLoad()时,这就是所有工作的队列。 我将暂时脱离所有这些,以使您了解这些队列与硬件的关系。 在这里,我提供了排队时任务的快照。 在继续之前,我想先介绍几个定义。 运行循环-您的程序只有在告诉您时才停止,而在运行时,它会在while循环下运行,直到结束。 有时它需要处理事物,而其他时候,它只是简单地通过循环而没有任何变化。 线程-简单地说,这些是您的单独任务,如果您的任务需要另一个任务来完成其自己的过程,它将在另一个线程中处理该任务。 (不要与CPU Core混淆) CPU —计算机的大脑,这是使用一个或多个内核执行计算的设备。 核心-核心是处理器的物理或逻辑部分,可读取您的代码并返回结果。 每个核心都有许多硬件线程,可用于执行在其上发送的任务。 CPU Clock Speed(CPU时钟速度)—处理器读取1s和0s(二进制)的速度。 如果您曾经想过1 GHz意味着什么,Giga意味着十亿,那么1 GHz意味着处理器的每个内核每秒可以读取10亿个1或0。 我的开发计算机的处理器速度为2.8 GHz,具有8个内核。 这意味着它可以在其基本时钟速度下每秒处理2.8 * 8 = […]
到目前为止,您已经熟悉“闭包”的定义以及它的基本用法,但是您感觉可以通过了解使用闭包还可以做些什么来扩大您的熟悉程度,这篇文章非常适合您! 就个人而言,我发现闭包是Swift中最酷的功能之一,我相信使用闭包可以使代码更具表现力,响应能力强并且易于处理。 甚至标准函数也被视为特殊的闭包(称为闭包)。 什么是自动关闭? 第一次阅读有关自动关闭的信息时,我发现它在理解使用它的目的时有些困惑,直到我发现没有必要对此进行过多思考,这确实很简单。 苹果将自动关闭定义为: 自动闭包是一种自动创建的闭包,用于包装将作为参数传递给函数的表达式。 它不带任何参数,并且在调用它时,它返回包装在其中的表达式的值。 这种语法上的便利性使您可以通过编写正则表达式而不是显式闭包来省略函数参数的花括号。 实际上,它仅是用于传递闭包作为参数的语法糖 。 将自动闭合功能作为函数参数传递时,不必键入花括号! 如何实现自动关闭? 实际上,您不希望将闭包本身作为参数传递给它,它与将闭包作为参数的函数有关。 通过将闭包参数标记为@autoclosure : func perform(closure:@autoclosure()->()) 您正在告诉编译器closure 是一个自动关闭功能,就这么简单! 为什么要使用自动关闭? 如上所述,在“什么是自动闭合?”中,在某些情况下,将闭合作为参数传递而没有花括号的情况变得更加方便。 我认为使用自动关闭功能的最佳位置之一是运算符 。 例: 为了使它更清楚,让我们来看一下这种情况: 想象我们正在开发与组织人力资源系统有关的产品的一部分,其中包含Employee 结构为: struct Employee { var id:Int 变量名称:字符串 可变薪水:UInt } 并已要求新的要求为: 我们需要创建一个运算符为( -! )来递减员工工资,应按以下方式使用它: 员工-! 量 金额将基于许多因素进行计算。 但是,如果雇员的工资少于1000,则什么也不会发生 太酷了! 我们将新的( -! )运算符称为“减量运算符”。 因此,我们将其实现为: 中缀运算符-! 扩展名员工{ 静态函数-!(lhs:inout Employee,rhs:()-> UInt){ 如果lhs.salary> […]
速查速查表—封闭 基本格式 2 。 让我们进化 目标:反转字符串数组 使用摩擦 使用闭包 1。 基本的 2.从上下文推断类型:闭包参数和返回值中没有括号 3.单一表达式的隐式返回:没有return关键字 4.速记参数namaes :使用$ 0,$ 1 5.运算符方法: 字符串类型定义了operator(>),所以只有运算符,没有括号,没有括号 3.更多发展:尾随封尾 写在函数调用的括号后面,即使它仍然是函数的参数。 4.闭幕式 swift闭包通过引用捕获上下文,通过值捕获,它使用捕获列表 。 Objective-C块按值捕获上下文, 按引用捕获, 使用__block关键字 价值之前。 OMG,默认情况下,objective-c块与快速捕获上下文相反。 捕获列表: [无主的自我] 捕获列表: [弱自我]在这种情况下自我是 可选 ,使用 守卫
啊,内存泄漏……起初,您甚至都不知道它们可以存在,然后您将其忽略,然后在不知道如何正确处理它们的情况下开始到处看到它们。 好的,所以现在也许是时候清楚地了解它们的时间,何时发生以及可以使用哪些工具摆脱它们了。 苹果公司发表了一篇很棒的文章,介绍了强有力的课堂参考周期。 很容易理解什么是内存泄漏以及在这种情况下如何避免内存泄漏。 但是,这是一种非常罕见的情况,并且很容易发现。 我发现有关闭包的部分更加令人困惑。 因此,让我们一劳永逸地阐明这一点。 带封闭的参考循环 首先,您必须了解闭包是什么以及闭包是做什么的。 我喜欢将其描述为一段代码,该代码在声明时会创建自己的临时类,该类包含对其执行自身所需的所有对象的引用。 让我们以一个简单的示例开始:一个具有CustomView的ViewController。 该CustomView有一个闭包,当点击按钮时会调用该闭包。 如您所见,我们有一个周期。 这意味着,如果退出此视图控制器,则无法将其从内存中删除,因为它仍被闭包引用。 这个例子很清楚,我们的viewController有一个属性subview ,它有一个属性onTap来捕获self 。 但是不幸的是,它可能变得更加复杂。 潜在周期的例子 您始终必须问自己的问题是: 谁拥有封闭件? UITableView 如果您曾经构建过iOS应用程序,则必须在某个时候处理UITableView,而且很有可能,您还必须使用自定义按钮来处理自定义单元。 这是快速完成此操作的一种方法,首先,您有一个CustomCell,它具有一个动作闭合,可让您定义点击按钮时发生的情况。 GCD 您当然已经处理过Grand Central Dispatch,可以发现是否有周期吗? 在TableView示例中,如果您unowned在onButtonTap闭包中放weak或unowned ,您将看到类似以下内容: 右侧的感叹号指示泄漏。 但是Xcode有时很难检测到泄漏。 您很可能有泄漏但没有感叹号。 在这种情况下,您只需要注意内存中的内容,如果看到不应该存在的内容,很可能会泄漏。
在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: […]
因为 曾经有个好主意说: 不要让任何东西变得足以摧毁你。 开玩笑! 这只是我自己想到的。 我正在修复错误。 我确实修复了它,但我不知道它会在其他功能上产生连锁反应。 我所做的只是在从主线程上的API提取数据后,仅更新UI。 这是一个主屏幕,我们在其中隐藏了我用来更新UI的功能内的导航栏(我不知道被隐藏的导航栏也位于该功能内)。 两天后,QA向我提出了一个错误,即从Home控制器转到另一个控制器后,导航栏在几秒钟后自动隐藏起来。 仅当您在应用程序打开后从Home转到另一个控制器时,才会发生该错误。 该错误真的很奇怪,因为在视图控制器的viewDidLoad中, setNavigationBarHidden设置为NO ,并且无法正常工作。 然后,我尝试在存在API调用的地方将setNavigationBarHidden设置为NO 。 这似乎也不起作用。 我在整个项目中搜索了setNavigationBarHidden ,发现唯一将其设置为YES的地方是一个未被使用的控制器。 这有点烦人,因为我似乎无法真正从setNavigationBarHidden的位置设置为YES 。 好吧,我当然很累,字面意思是: 因此,我决定向同事寻求帮助(你们也应该尝试一下。当您讨论事物时,它总是有帮助的)。 首先,他还尝试了与我相同的方法,然后为了调试setNavigationBarHidden属性,我们决定覆盖 setNavigationBarHidden属性,并查看从何处设置该属性(我不知道为什么一开始我就没想到它)。 调试后,它使我进入了两天前在Home控制器的主线程内调用的UI更新功能。 因为UI更新功能是在dispatch_get_main_queue()内部编写的,所以它是一个闭包。 不可避免地,将Home控制器的自身捕获到内部,这导致导航栏隐藏。 因此,通过在weaks_get_main_queue dispatch_get_main_queue()内部提供弱更新的UI更新功能可以解决此问题。 对于所有想知道为什么我只找到一个setNavigationBarHidden集的人 搜索整个项目后,请选择“是” 。 原因是用于隐藏导航的属性,直接有navigationBarHidden而不是它的setter。 我的错。 原谅我太人性化了。 😀 是的,仅仅是一个强大的封闭/障碍 会浪费很多时间。 学过的知识!