预习 资源 项目 https://github.com/calmone/iOS-UIKit-component 参考 UITextChecker https://developer.apple.com/reference/uikit/uitextchecker UITextField https://developer.apple.com/reference/uikit/uitextfield 快乐编码😄
使用Bitrise四个月后,我觉得我应该与社区分享此工具的强大功能。 快速介绍自动化并了解为什么我们确实需要自动化工具将是很好的。 让我们从快速介绍iOS自动化开始,看看新工具如何加快我们的开发速度。 开发,测试和部署团队需要大量的精力和时间。 特别是,如果要手动执行所有这些步骤。 您必须在每个步骤上都小心谨慎,以避免可能的错误。 使整个开发/测试过程自动化可以提高软件产品的质量,并为您和您的团队节省大量时间。 在自动化过程中,您应该了解一些步骤,例如持续集成,持续交付和持续部署。 让我们简要地解释一下它们: 持续集成 假设您的团队有多个开发人员从事同一项目,而您正在从事Git。 假设一个开发人员发出了“拉取请求”,则所有单元测试都可以在共享计算机(远程或本地)上运行。 测试完成运行后,您知道它们成功或失败。 如果测试通过,则可以开始进行代码审查。 否则,开发人员将收到测试失败的通知,应进行某些修复。 一切准备就绪后,可以轻松合并代码。 此过程称为持续集成,它可以帮助您自动进行开发,测试和集成过程,而不会浪费大量时间。 持续交付 功能或冲刺的每个构建周期称为“持续交付”。 您可以交付功能/冲刺分支以进行持续集成。 如果您已经知道Stack Overflow和Trello的联合创始人Joel Spolsky ,您可能听说过他有一个名为“ Joel Test”的测试。 它衡量软件开发团队的素质,以获取更好的代码。 “进行日常构建”是为他改进代码的重要步骤之一。 如果要检查所有步骤,请单击下面的链接: Joel测试:改进代码的12个步骤 您听说过SEMA吗? 这是一个相当深奥的系统,用于衡量软件团队的水平。 不,等等! 别… www.joelonsoftware.com 持续部署 我认为自动化最迷人的部分是持续部署。 假设您的开发分支已经过测试,可以部署了,Continuous Deployment允许您直接从存储库中上传应用程序。 大多数iOS开发人员认为部署是开发过程中最痛苦的部分之一。 因为有多个步骤将应用程序部署到App Store,并且如果出现错误或问题,您会在过程的“任何”状态下看到一个错误窗口。 确实很烦人,因为您必须对应用程序进行签名,存档并将其上传到iTunes Connect。 如果发生错误,半小时后您甚至可能会看到错误消息。 因此,您应该使其自动化,这样您就不会再浪费太多时间。 我希望本摘要有助于在了解Bitrise之前了解持续集成/交付/部署之间的区别。 有很多自动化工具,例如Jenkins,Travis,Circle,Buddybuild和Bitrise。 他们每个人都提供不同的解决方案和经验。 我决定使用Bitrise代替其他工具。 因为Bitrise: 专为移动应用而构建, 有一个免费的CI计划,没有时间限制, 拥有良好的用户体验, 有充分的文档证明,并且部分开源; […]
我最近遇到了Soroush Khanlou的Coordinator模式讨论,并决定在他的博客上阅读更多内容:http://khanlou.com/2014/09/8-patterns-to-help-you-destroy-massive-view-controller/但它变得非常混乱,我研究并经历了人生,直到我终于明白了! 这种模式可以帮助我们正常地在应用程序内管理从一个视图到另一个视图的导航。 我确定您已经看过几次此代码 让 vc = ViewController() vc.object = NSObject() 自我 .navigationController?.pushViewController(vc,动画: true ) 但不是! 这仅表示子控制器正在告诉父控制器显示,这是您的不尊重吗? 这种设计coordinator pattern将有助于将其他viewController的表示coordinator pattern封装到一个单独的对象中。 Soroush并不是唯一讨论这种将导航职责移到视图控制器之外的模式的iOS开发人员。 在标题下可以找到其他几篇文章:Krzysztof Zablocki,Alberto Debortoli等人讨论的流量控制器 。 我将直言不讳,因为无需解释Soroush如何提出这种模式的故事。 您在这里看到集成有多么容易,以及是否想采用它。 PS:我自己对协调器模式的实现可能与您之前看到的有所不同,因为每个人都只是使用对他们有用的东西 假设我们正在构建具有以下功能的应用程序 认证方式 一世。 登录 ii。 注册 家 轮廓 请注意,这些都是功能,而不是控制器。 重要的是要注意,每个功能都可以在其下具有多个控制器,并具有一个协调器来处理它们之间的导航。 现在让我们开始吧! 首先,我们需要创建我们的基本协调器协议。 它看起来像这样 协议协调员:类{ var childCoodinators:[协调员] { 获取 设置 } var navigationController:UINavigationController { 获取 设置 } func […]
在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: […]
从客观的c背景出发,枚举,类和结构之类的组件之间的区别对我来说非常明显:Enum是一组命名值,Struct是结构化数据类型,当然Class允许我们创建具有所有POO相关的东西。 当我第一次开始学习Swift时,这有点令人困惑。 从某个时候开始,它们可能看起来很相似。 在许多其他语言中仅使用类的情况下,可以很快找到Structs。 例如:Enums和Structs也可能具有方法或构造函数。 我个人需要一些时间来快速熟悉结构和枚举的扩展功能。 所以为了知道在哪里使用每个。 重要的是要清楚地了解什么使一个人与另一个人不同。 因此,让我们尝试一个接一个地检查它们。 一方面,类之间的枚举和结构之间的主要区别。 是类是引用类型 ,而枚举和结构是值类型 。 这意味着当您将一个类类型对象分配给另一个对象时。 他们成为 指向同一实例。 因此,当一个被修改时,该修改将应用于另一个: class Cat {var name:String init(name:String){self.name = name}} var cat1 = Cat(name:“ Kitty”)var cat2 = cat1cat1.name =“ Oscar” //两只猫都是相同的print(“ cat1 name:\(cat1.name),cat2 name:\(cat2.name)”) // cat1名称:奥斯卡,cat2名称:奥斯卡 而对于结构和枚举,将在每次分配时创建一个新副本: struct Cat {var name:String} var cat1 = Cat(name:“ Kitty”)var cat2 = cat1cat1.name =“ Oscar” […]
Swift在Airbnb的简史 在2014年的WWDC上,Apple用一种新的语言:Swift使我们感到惊讶。 在Airbnb,我们很快跃居第一,并在2014年8月甚至在Swift达到1.0之前就编写了第一行Swift。 那年晚些时候,苹果发布了Apple Watch和WatchKit。 考虑到社区对传闻已久的Apple Watch的兴奋,我们在2015年4月打赌,开始完全在Swift 1.1中编写Airbnb的Apple Watch应用程序的第一个版本。 在WWDC 2015上,Apple正式宣布了Swift 2.0。 因此,当需要构建Apple TV应用程序时,我们尝试了一下并使用Swift 2.0进行了编写。 在这两个成功的试验之后,我们于2016年1月决定要在Swift 2.0中编写所有新功能。 一切进展顺利,直到“大雨燕”改名降落。 为了升级到Swift 3,我们要求一个由两个人组成的团队在5周的时间内进行代码库的迁移。 幸运的是,升级到Swift 4更加简单。 自2017年10月以来,我们的整个代码库都位于Swift 4中。 为什么要使用风格指南? 斯威夫特是一门年轻的语言。 当我们在2014年开始使用它时,我们还没有标准化的Swift样式指南。 我们让15位工程师在我们的代码库中放松下来,他们每个人都以自己的个人Swift风格编写。 很快变得很清楚,如果我们不同意标准化的风格,我们要么花太多时间讨论PR中的风格,要么我们的代码库就像杰克逊·波洛克的画。 当我们在使用Apple TV应用程序时,我们开始了一份非正式的风格指南。 在2016年1月,这与其他临时工作相结合,成为了正式的Airbnb Swift样式指南,我们开始合作定义在Airbnb上编写Swift的首选方式。 苹果和Swift社区为如何编写Swift提供了宝贵的指导。 即使他们绝对影响了我们在Airbnb上编写Swift的方式,我们仍然认为保留自己的样式指南是一种有价值的方法,可以迭代对我们认为正确的事情,同时与社区保持一致。 这就是为什么我们将Apple的建议添加到我们的指导原则中的原因。 我们不想手动识别和更正违反样式指南的行为,因此我们分别采用了Swift社区中最受欢迎的linter和formatter,分别为SwiftLint和SwiftFormat。 在我们的样式指南中,您将找到我们的SwiftLint和SwiftFormat配置。 如果您想使用与我们相同的规则,只需抓住它们并开始在您的项目中使用它! 我们为什么要公开采购? 自从我们开始编写Swift以来,已经过去了很多年,并且社区已经在某些模式上实现了标准化。 Swift语言和社区对我们来说很棒,因此我们想通过分享一些我们在Airbnb上编写Swift所用的模式来做出贡献。 我们了解并非所有人都会同意我们在Airbnb的工作方式。 我们相信有异议的人,我们很想听听您的反馈-我们很高兴分享我们的想法。 如果您不同意或认为我们缺少什么,欢迎您的贡献! 拥抱斯威夫特 在Airbnb,我们将Swift视为iOS开发的未来,并且我们将继续推动尖端本机技术的发展。 鉴于我们即将淘汰React Native,我们将在内部Swift和Kotlin库中投入更多资源。 我们70%的新本地Android代码是用Kotlin编写的,而90%的iOS是用Swift编写的。*我们一直在迁移到最新的语言功能。 *不包括旧版React Native代码。
很少有数据结构像堆栈那样普遍存在。 它们易于理解和实现,但它们的强大之处在于强大。 本文的目的是解释什么是堆栈以及如何实现堆栈,并介绍三个实际用例。 让我们开始吧! 在 此处 克隆本文随附的存储库 。 说明:堆栈与数组 堆栈是一种结构,负责遵循LIFO原理(后进先出)动态地收集数据。 打个比方,您可以想象一堆自助餐厅托盘:当您要添加一个新托盘时,它将被引入到堆叠顶部(而不是插入其中)。 由于最后一个纸盘在纸堆的顶部,因此当需要一个单独的纸盘时,它也将是第一个脱落的纸盘。 堆栈提供两个主要功能:“推动”或引入一个新元素,以及“弹出”或除去最后一个元素。 如果我们将此结构与典型数组进行比较,就会发现一些明显的区别。 尽管Swift会以智能方式处理数组的内存分配,但在基础语言中,数组容量是在初始化期间设置的,并且是静态的。 另一方面,堆栈根据需要为单个节点分配和取消分配内存,这使它们非常灵活。 此外,数组允许访问任何索引的元素,而堆栈仅与终端节点进行交互。 尽管这似乎很有限(确实是……),但它实际上使数据访问非常轻巧且快速。 此外,LIFO行为对于解决特定情况可能非常有用,我们将在本文后面介绍。 堆栈:演示实现 有几种方法可以实现堆栈,但是在本演示中,我们将创建一个双向链接列表,该列表清楚地演示了在引入新元素时的动态内存分配。 首先,让我们仅查看所需的类和属性: 接下来,让我们看一下如何将新元素压入堆栈。 步骤1:使用所需的值创建一个新节点。 步骤2:假设endNode指向一个节点,我们可以将端节点中的下一个属性分配给新节点,并将新节点中的前一个属性分配回端节点。 请记住,先前的属性很弱,因此我们避免了保留周期。 步骤3:最后,我们可以通过访问endNode的next属性将其endNode指针移至newNode。 请注意,列表所需的内存随着newNode的分配和初始化而增长。 我们的pop()方法删除端节点并返回该节点中的值。 步骤1:我们将值存储在端节点的临时常量val中 。 步骤2:我们通过使用endNode指针的先前属性将其向后移动一个元素。 步骤3:我们将endNodes的next属性设置为nil。 现在,最后两个节点之间的唯一参考是通过标记为弱的先前属性。 这意味着从内存中释放了该节点。 步骤4:我们返回最后一个节点中的值。 在解释了这些重要方法之后,让我们看一下Stack类的最终实现: push和pop方法的出现与我们期望的完全一样(第13–32行) 。 我们可以使用push方法创建带有一些可变参数值的自定义初始化程序(第7-11行)。 另外,我们可以通过检查rootNode是否具有值(第34–36行)并具有基本的打印方法(只要它能够通过下一个属性访问节点)来遍历列表(第38–36行) ,以检查堆栈是否为空。 44) 。 我们的堆栈功能的基本测试如下所示: 知道如何实现堆栈是一回事,但更重要的是识别适合堆栈的情况。 在下一部分中,我们将研究三种此类情况。 用例1:冲销订单 因为堆栈的顺序是固定的,所以通过将元素从一个堆栈弹出并立即放在另一个堆栈上可以非常容易地实现逆序。 不用乱搞索引! 用例2:测试对称性 堆栈的另一个好用例是测试对称性。 在下面的示例中,我们正在测试一串括号,以确保每个闭合括号与先前的打开括号正确匹配。 我们首先检查字符数是否可以被不整数(第6行)立即除以2的奇数个字符。 接下来,我们通过定义一个非法字符字符集来检查我们是否具有有效的输入,然后检查我们的输入字符串是否包含零个非法字符范围(第7-8行) […]
在之前的文章中,我提到了一种为私有方法编写单元测试的方法。 你们中的许多人对此可能性感兴趣,并想了解更多。 我认为这将有助于为您提供一个可以遵循的教程,因此请继续。 如果您回想起上一篇文章,我说过微框架是解决此问题的一种方法。 什么是微框架? 没什么特别的,只是导入到主应用程序目标中的一个小框架。 为什么这样做 任何具有内部访问级别的内容都可以在其测试模块的单元测试目标中访问。 然后,将相同的框架导入到主应用程序目标后, 内部实体将无法访问,或者出于所有实际目的变为私有。 如果所有这些听起来像胡言乱语,请不要担心。 让我们通过一个小教程逐步完成它。 入门 继续并从Github获取入门项目。 这里没有什么特别的事情,它只是一个空的单视图应用程序。 由于这是一个有关微框架的教程,因此,我们转到File-> New-> Target来创建一个新框架。 框架是一种目标。 它是一个代码模块,可以导入到另一个标记中,例如您的主应用程序的目标。 停留在iOS上,并一直向下滚动。 选择“ Cocoa Touch Framework”,然后单击下一步。 您将被带到另一个屏幕,您可以在其中命名您的自定义框架。 遵循Apple的命名约定,我选择将其命名为CoreTrick。 选中包含单元测试复选框非常重要。 这就是让您为要导入的框架编写单元测试的原因。 单击“完成”,然后在您的项目上单击以再次检查一切是否正常。 如果遵循正确,您将看到一个应用程序目标,一个应用程序目标的单元测试目标,一个框架目标以及该框架目标的另一个单元测试目标。 TrickTrackerTests是TrickTracker的单元测试目标,TrickTracker是主要的应用程序目标。 CoreTrickTests是CoreTrick的单元测试目标,CoreTrick是框架目标,它将包含您要测试的所有实体。 大! 您已经准备好开始编写一些代码。 让我们创建一些内部实体并对其进行测试 通过内部 , 我只是指与他们相关的访问级别。 函数,变量,类,枚举和结构都可以标记为internal 。 这仅表示这些实体只能在定义它们的模块内访问。 在这种情况下,那就是CoreTrick框架。 我确定您还熟悉其他访问级别。 Public表示可以在模块外部访问实体。 打开意味着它可以在模块外部访问,并且可以被子类覆盖。 私有意味着只能在实体本身的范围内访问它。 单板滑雪特技动作实体 我们的Snowboard Trick Tracker应用程序可跟踪您的滑雪技巧(phe们说快了五倍!)。 它使用具有一些基本属性的简单Snowboard Jump Trick实体。 创建一个名为SnowboardJumpTrick的新Swift文件,并将以下代码粘贴到其中。 […]
预习 资源 项目 https://github.com/calmone/iOS-UIKit-component 参考 UISwitch https://developer.apple.com/reference/uikit/uiswitch 快乐编码😄
在本博客中,我将主要撰写有关软件开发,Swift,iOS,机器学习,算法和到目前为止我学到的其他有趣主题的文章。 没有世界,就不可能有程序员的博客! 因此,您在这里: let hello = “Hello World” 当然在Swift😉 但是,为什么要创建一个新博客? 博客还不够吗? 几个原因😉 我想在2016年创建此博客。实际上我当时写了两篇文章,但从未发表过。 帖子差不多完成了,博客也差不多完成了。 我只是还有其他更紧急的项目需要处理。 至少那是我对自己说的。 因此,第一课是: finish what you have started 。 无论如何,只需完成即可。 我已经遵循这种模式已有一段时间了。 第二个原因更为重要- learning while blogging 。 当您想向他人解释刚刚学到的东西时,这是完全不同的事情。 突然,您意识到您不确定事物在幕后的实际运作方式。 为了撰写有关它的博客文章,您需要更深入地研究,阅读文档并收集更多信息。 这都是关于学习的。 第三个原因- connecting with others 。 博客使您与人更近。 您会惊讶于其他人如何解决您面临的问题。 把自己放在那里,让别人看看你怎么说。 原因四: give back to the community 。 多年来,我一直在使用开放源代码库,并向其他博客学习。 现在该做出贡献了。 让其他人向您学习。 交流思想,分享知识。 最后但并非最不重要的writing is […]