Tag: swift

为什么我要编写快照测试?

测试是任何高质量软件的组成部分。 我相信每个公司或软件发行商都必须先验证产品的质量,然后才能投放市场。 据说,如果质量好,它将吸引更多的用户。 这个事实也适用于软件开发。 我们以手动或自动方式执行UI测试,以确认应用程序的行为正确并具有符合规范的所有功能。 如果我们进行更细化的单元测试,则可以测试单个单元。 我们通过编写肯定的测试(即正确通过测试)和否定的测试(即测试意外数据到来时单元的行为)来涵盖所有极端情况。 编写自动化测试以捕获UI“正确性”实际上是不可能的。 测试UI困难的原因是,UI最小模块的显着细节很难以编程方式表达。 正确性不能由输出的文本部分确定。 我们希望质量保证将重点放在需要人工关注或可以通过自动化完美测试的功能的确切状态下的确切组件上。 但是UI单元测试呢? 好吧,我们为此提供了一个解决方案: 快照测试! iOSSnapshotTestCase如何捕获快照? iOSSnapshotTestCase提供FBSnapshotVerifyView(view)方法来将期望与参考快照进行比较。 如果不存在参考快照,它将捕获。 这个方法使用`renderInContext()`来捕获快照,但是`renderInContext()`有一些限制,您不能使用它来测试Visual元素或UIAppearance。 为了测试这些元素,还有另一种方法“ drawViewHierarchyInRect”。 要使用此方法,您需要在测试中设置`useDrawViewHierarchyInRect = true`。 drawViewHierarchyInRect的性能不好,所以我建议仅在确实需要时使用useDrawViewHierarchyInRect = true。 iOSSnapshotTestCase如何比较快照? 有很多比较图像的方法。 我在演讲中得到的第一个答案是逐像素比较图像,这是正确的,但在逐像素比较之前,我们还需要考虑其他方面。 让我们看看它如何进行比较: 首先,它比较图像大小。 如果不匹配,则测试失败。 如果容差率为零,则使用C函数“ Memcmp()”在内存级别比较图像。 为此,它使用calloc()在内存中分配空间,并使用CGContextRef在内存中绘制图像。 如果容差率> 0,即表示您可以接受,即使存在x%的差异,它也会通过对numberOfPixels(即图像宽度*高度)进行迭代来逐像素比较图像。 iOSSnapshotTestCase的功能: 它会根据测试类和选择器自动命名磁盘上的参考映像。 如果要在单个测试方法中执行多个快照,则需要提供一个可选的“标识符”。 使用`isDeviceAgnostic`。 如果您在测试中将此属性设置为true,它将在测试名称中附加设备型号,操作系统编号和大小。 优点: 快照测试易于编写。 在执行重构时,您不必担心,就好像只有代码重构一样,测试也不会失败。 解耦:视图将松散耦合。 易于验证不同尺寸的布局。 我建议以一个模拟器(即iPhone 6)为基础来捕获快照。 如果您使用3倍快照的iPhone 8,则尺寸会很大。 如果您使用的是CI / CD工具,请确保也在那里设置了默认模拟器iPhone 6。 […]

服务器端Swift的启动和运行:第1部分-待办事项列表项目设置

我已经想要了一个基本的,基于浏览器的待办事项列表。 没有任何干扰的东西。 使用Swift构建此库,并了解一些涉及的库似乎是一个不错的起点。 这是一个分为4部分的系列文章,概述了如何设置项目,路由入门,数据库设置以及最终创建应用程序的模型和控制器。 介绍 第1部分将概述一个基本的项目设置,包括使用swift软件包管理器,并让我们开始使用Swift从服务器返回响应中的一些文本。 项目设置 首先,让我们为项目创建一个目录,然后导航到该目录。 mkdir WhatsNext cd WhatsNext 接下来,我们将使用swift软件包管理器创建一个swift可执行软件包。 swift package init –type可执行文件 现在,生成一个xcode项目。 迅捷包generate-xcodeproj 打开项目并切换到第二个目标。 生成并运行,您应该会在控制台中看到“世界,您好!”。 打开WhatsNext.xcodeproj 完美的服务器设置 添加perfect-HTTPServer作为项目的依赖项。 打开Package.swift并将以下内容添加到您的依赖关系中。 .package(网址:“ https://github.com/PerfectlySoft/Perfect-HTTPServer.git”,来自:“ 3.0.0”) 还要将”PerfectHTTPServer”添加为目标的依赖项。 如果您使用的是Swift 3,则上述语法可能会遇到问题。 你可以在这里找到更多。 您最终的Package.swift应该看起来像这样…… 现在,回到终端并更新项目相关性并重新生成xcodeproj。 快速软件包更新 迅捷包generate-xcodeproj 假设没有问题,请将以下导入添加到main.swift的顶部,然后构建并运行。 导入PerfectLib 导入PerfectHTTP 导入PerfectHTTPServer 服务器需要服务 因此,我们的Web服务器需要提供目录或文件。 为了简单起见,我们将在我们的项目中创建一个名为webroot的文件夹,并在其中添加一个文件供我们的项目使用。 mkdir Webroot 触摸webroot / hello.txt 迅捷软件包regenerate-xcodeproj 添加一些占位符文本以了解正在提供文件。 接下来,我们需要在main.swift创建服务器。 我们创建一个服务器,设置其端口和documentRoot,启动它并捕获它将引发的任何异常,例如该端口已被使用。 在运行之前,我们需要将目标的文档根目录设置为项目目录。 为此,选择第二个目标,然后edit sceme […]

迅捷+守卫

让我们承认这一点,我们所有人都想编写“干净的代码”,这对于任何阅读它的程序员都是可以理解的。 很多时候,当我们寻找解决问题的最佳方法时,往往会编写草率的代码,只有我们才能理解 编写干净的代码不仅帮助我们更好地了解代码的结构和目的,而且还帮助将来打算从事该项目的开发人员。 我们可以采用多种方式来组织项目/代码。 其中之一是Swift中的后卫声明。 这种语言的未来具有很多优势,我将在后面的文章中解释。 句法 根据学者的说法,警卫声明的定义是:“一种构造,用于在不满足一个或多个条件的情况下将执行转移到范围之外。”语法很干净,看起来像这样: 现在我们来看看语法,让我们深入了解一下优势, 干净的代码,它确实显示了代码的意图 用例是直接且有目的的 同事和其他开发人员可以了解此代码的功能。 如果您现在已经进入iOS开发一段时间,您还记得在表视图中使用此if语句并实现UITableViewDelegate的情况,如下所述: 如您所见,这是一个实现UITableViewDelegate的可靠示例。 这是一个巨大的代码,但是带有警卫声明,代码更易于理解和安全。 现在花点时间思考一下您曾经使用过的所有这些时间以及是否要检查很多事情。 我可以想到很多例子,例如: 此用户名文本字段是否已填写? 此密码文本字段是否已填写? 布尔是对还是错? 用户是否可以连接互联网? 最后的想法 我真的很喜欢警卫声明。 一开始很难适应它,但是现在我可以找到一千种方法,迅速的功能可以帮助我编写更好的代码-更干净的代码。 希望您喜欢阅读这篇文章。 我很想知道您对后卫声明的想法。 让他们留在回应中,这样我们就可以在那里继续讨论。 我要感谢Tom Fox和Aryan Kashyap为我提供了一些有关本文初稿的建议。

Ben&iOS和Yazılım

本 Türkmenistanlıbir iOS开发人员,İstanbulÜniversitesinde “ Bilgisayaröğretmenliğive teknolojieğitimi” öğrencisi。 iPhone iletanışmasüreci Ben ilk defa Apple ile 2012’de iPhone 5 iletanıştım。 iPhone的iPhone屏幕快照androidtaraftarıydımçünküiPhone’unbazısınırlarıvardı(dosyapaylaşımı,iTunes的kullanmazorunluluğuvs…)。 iPhone’u elimealdıktan颂歌iPhonehayranı“aşığı” olmayabaşlamıştım。 Bilmiyorumhiçdenk geldiniz mi ama genellikle iPhone和Androidfanlarıdiyekarşılaştırırlarfanlarını。 斯坦福大学历史学院学报CS193P史蒂芬·乔布斯的下一个电脑史蒂芬·乔布斯的下一张电脑保罗·汉格蒂·贝尔·史蒂夫·乔布斯和史蒂文·乔布斯,史蒂文·乔布斯,史蒂芬·乔布斯 科萨卡: 纽约时报》的Yayınlananbiryazıda,可能是iphone kullananinsanlarınbeyni beyinaraştırmasıyapan insanlartarafındantaranmış。 Beklediklerisonuçbağımlıinsanlarınbeyindokularınabenzer bir beyin dokusu ikenaşıkolaninsanlarınbeyindokularıylaaynıdokuya sahipolduklarıortayaçıkmış。 保罗·赫加蒂(Paul Hegarty): Belki“Aşık”değilimdiramabüyükbir iPhonefanıyımdiyerek ilerlemek istiyorum。 VeYazılım Yazılımlatanışmam10.Sınıftaolmuştu。 Türkmenistandaliselerdeayrımolmadığıiçin(sadecedüzlise)meslek lisesiseçipyazılımayönelmegibi birşansımolmadı。 Ama bilgisayaröğretmeniminözeluğraşlarıylabilgisayarlara veyazılımahayran olmayabaşlamıştım。 […]

迅捷的Singleton模式

Singletons模式提供了对象的全局可访问共享实例。 在大多数情况下,您在iOS中不需要单例(这可能会被滥用以形成结构不良的代码),但是在某些情况下,仅拥有一个类的实例是有意义的。 。 苹果公司经常使用这种方法。 例如:UIApplication.sharedApplication(),NSUserDefaults.standardUserDefaults(),NSFileManager.defaultManager()均返回Singleton对象。 在Objective-C中 ,为确保仅创建一个单例对象的实例,将其初始化包装在调用dispatch_once函数中,该函数在应用程序的生命周期内一次执行一次块。 在Swift中 ,使用静态类型属性只是必要的,即使同时访问多个线程,该属性也只能被延迟初始化一次: 就是…单线单人! 用法是: Singleton.sharedInstance 由于所有对象都在Swift中带有默认的公共初始化程序,因此我们需要覆盖init并将其设为private 。 这样可以确保单例确实是唯一的,并防止外部对象创建自己的此类实例。 Singleton Shoudl也是最终版本,以防止将其子类化(如果Singleton需要其他功能,则应将其封装在扩展中)。 因此,我们需要添加另一行: 这是Singleton的最终正确实现。 感谢Michael Ormonde提出的“私有初始化”建议。 希望本文对您有所帮助。 谢谢阅读!

在iOS的Swift 3中编写Cordova插件

本文是对我在2016年4月写的一篇文章的更新,并且已被修改为使用Xcode 8.2支持的“现代” Swift 3语法。 此外,它已更新为使用Cordova 6.4.0。 您可以在 此处 找到使用Swift 2语法的原始文章 。 自2008年App Store首次开放以来,希望开发iOS应用的开发人员必须学习Objective-C。 这包括那些选择使用Apache Cordova的混合模型的人,因为在Objective-C中还编写了可扩展Cordova覆盖本机API的插件。 长期以来,这是可用于iOS开发的唯一语言。 事情在2014年发生了变化,当时苹果在当年的全球开发者大会上发布了Swift编程语言。 从那时起,苹果一直在不断发展Swift语言,分别发布了版本2和版本3,并更新和改进了语言语法,并于2015年底开放了源代码。这引起了人们对于使用该语言进行本机应用程序开发以及其他方面的极大兴趣。 Cordova混合应用程序开发人员可以继续使用平台生态系统提供的出色的现成设备API插件,但是经常需要编写特定于项目的插件。 虽然Cordova的CLI生成的核心应用程序代码继续使用Objective-C,但是开发人员现在可以在制作自己的插件时在Objective-C或Swift之间进行选择。 让我们看一下复制在上一篇博客文章中使用Objective-C构建的“ ModusEcho”插件所涉及的内容。 这次,我们将使用Swift作为本机代码。 回顾一下,此插件借鉴了Cordova文档中的“ echo”示例,并具有两个功能: echo:带有字符串参数,显示“ Toast”(本地对话框,显示在短时间后自动关闭的消息),并将传递给它的字符串返回给调用者 echojs:带有字符串参数,将传递给它的字符串返回给调用方,完全用JavaScript实现,没有本机代码 初始插件创建 和以前一样,Plugman可以通过创建插件支架来帮助我们前进,就像Cordova CLI对新应用程序所做的一样。 我们可以创建一个新的“ ModusEchoSwift”插件,如下所示: 插件创建-名称ModusEchoSwift –plugin_id com-moduscreate-plugins-echoswift –plugin_version 0.0.1 –path modusechopluginswift 这不会将任何输出记录到控制台,但是会在“ modusechopluginswift / ModusEchoSwift”中设置支架。 在该文件夹中,我们可以找到Plugman生成的样板plugin.xml: ModusEchoSwift 让我们更改“ clobbers”元素,通过更新plugin.xml使其看起来像“ modusechoswift。”,使Cordova应用程序可以访问我们的插件函数: ModusEchoSwift 保存更改后,我们现在可以查看插件的JavaScript界面​​。 实施通用JavaScript接口 Plugman创建的初始JavaScript模块“ www / […]

使用KeyPath在Swift中进行无缝数据操作

本文是对 KeyPathKit 框架背后思想的详细介绍 。 如果您喜欢您将要阅读的内容,我敦促您看一下图书馆必须提供的所有功能😉 非常感谢 JérômeAlves 向我展示了我将在下面描述的一种方法。 Swift 4引入了一个称为KeyPath的新概念。 它允许开发人员处理特定类型的特定属性。 稍后,他们将能够针对指定类型的对象评估此句柄,以便为其属性获取值: 最重要的是,此过程完全是类型安全的,并且与struct和class都兼容,并且其语法灵活而简洁:您可以使用类型推断(例如\.count将是有效的)并且可以轻松地链接属性(例如\UIView.layer.cornerRadius是有效的KeyPath ) 现在考虑以下示例数据: 用例进行改进 假设我们要过滤掉lastName不是”Webb” 。 使用filter ,我们可以按照以下方式编写: 现在,我们尝试重写此代码,以便使用KeyPath而不是闭包: 呼叫站点看起来已经干净了一些,而且在不关闭的情况下也更易于阅读。 但是最好的还没到。 现在想象一下,我们想要保留其lastName遵循使用正则表达式指定的特定模式的值。 现在,如果我们只想获取名称以”son”结尾的联系人,则可以如下编写: 这种语法看起来确实很干净,并且比闭包可以实现的可读性高。 谓词介绍 让我们回到第一个用例,再次比较两种语法: 第一种语法具有直接使用运算符==的优势,当人们快速浏览代码时,该运算符提供了宝贵的视觉线索。 第二种语法的优点是不需要闭包,这使代码更加简洁。 如果我们将它们的优点结合在第三种语法中怎么办,那将使我们能够编写: 当然,那看起来不错! 👍 那么如何实现呢? 首先要开始的是运算符== 。 在Swift中,我们习惯于在Equatable类型的上下文中定义此运算符。 在这种情况下, ==返回Bool 。 但是完全有可能重写==以使其返回Bool以外的其他值。 为了解决我们的问题,我们将编写一个返回Predicate的重载。 什么是谓词? 您可以将其视为表达对特定类型的值的约束的一种方法。 一旦定义,就可以针对指定类型的特定值评估谓词。 首先,我们定义一个类型来实现KeyPathPredicate : 然后,我们重载==以使其采用KeyPath并且常量具有参数并返回KeyPathPredicate : 最后,我们定义一个与KeyPathPredicate一起使用的filter版本: 而且,瞧,我们现在可以使用目标语法来编写代码🎉 结论 为了使本文的长度合理,我仅考虑了一些基本用例。 但是还有许多其他用例需要讨论。 例如,最好重载运算符~=以便根据正则表达式评估String值。 […]

键盘观察器(快速)

为什么要观察员? 有时了解键盘何时弹出会很有用,这样我们就可以在视图中进行一些额外的更改或使用额外的代码来调用某些函数。 UITextFields足以获取状态。 但是观察者到键盘还是一个加点。 管理键盘 尽管许多UIKit对象会根据用户交互自动显示键盘,但是您的应用仍然承担一些配置和管理键盘的职责。 以下各节描述了这些责任。 接收键盘通知 显示或隐藏键盘时,iOS会将以下通知发送给任何已注册的观察者: UIKeyboardWillShowNotification UIKeyboardDidShowNotification UIKeyboardWillHideNotification UIKeyboardDidHideNotification 每个键盘通知都包含有关键盘在屏幕上的大小和位置的信息。 您可以使用UIKeyboardFrameBeginUserInfoKey和UIKeyboardFrameEndUserInfoKey键从每个通知的userInfo词典中访问此信息。 您应该始终在这些通知中使用该信息,而不是假设键盘是特定大小或特定位置。 键盘的大小不能保证从一种输入方法到另一种输入方法都相同,并且在不同版本的iOS之间也可能会变化。 此外,即使对于单一语言和系统版本,键盘尺寸也可能根据应用程序的方向而有所不同。 例如,图4–3显示了纵向和横向模式下URL键盘的相对大小。 使用键盘通知中的信息可确保您始终具有正确的尺寸和位置信息。 显示键盘 当用户点击一个视图时,系统会自动将该视图指定为第一响应者。 当包含可编辑文本的视图发生这种情况时,该视图将针对该文本启动编辑会话。 在该编辑会话开始时,视图要求系统显示键盘(如果尚未显示)。 如果键盘已经可见,则第一响应程序中的更改会将来自键盘的文本输入重定向到新轻击的视图。 因为当视图成为第一响应者时会自动显示键盘,所以您通常不需要执行任何操作即可显示它。 但是,您可以通过调用可编辑文本视图的becomeFirstResponder方法来以编程方式显示该键盘。 调用此方法会使目标视图成为第一响应者,并开始编辑过程,就像用户在视图上轻按一样。 如果您的应用程序在一个屏幕上管理多个基于文本的视图,则最好跟踪当前哪个视图是第一响应者,以便您以后可以关闭键盘。 解除键盘 尽管通常会自动显示键盘,但系统不会自动关闭键盘。 相反,您的应用有责任在适当的时间关闭键盘。 通常,您将根据用户操作来执行此操作。 例如,当用户点击键盘上的“返回”或“完成”按钮或点击应用程序界面中的其他按钮时,您可能会关闭键盘。 根据配置键盘的方式,可能需要向用户界面添加一些其他控件,以方便键盘的退出。 要关闭键盘,请调用当前作为第一响应者的基于文本的视图的resignFirstResponder方法。 当文本视图退出其第一响应者状态时,它将结束其当前的编辑会话,将该事实通知其委托人,并关闭键盘。 换句话说,如果您有一个名为myTextField的变量,该变量指向当前是第一个响应者的UITextField对象,那么解除键盘的操作就像执行以下操作一样简单: 让我们开始使用代码… 1:创建一个函数并将观察者添加到键盘。 //将观察者添加到键盘通知中 fileprivate func watchKeyboardNotifications(){ NotificationCenter.default.addObserver(自身,选择器:#selector(keyboardShow),名称:.UIKeyboardWillShow,对象:nil) NotificationCenter.default.addObserver(自己,选择器:#selector(keyboardHide),名称:.UIKeyboardWillHide,对象:nil) } 2:隐藏键盘并显示键盘功能。 //隐藏键盘 @objc func keyboardHide(){ //编写代码行以隐藏键盘,并在隐藏键盘之前对要执行的额外行进行编码。 } //显示键盘 […]

创意简洁编码

本周,我们在有关参数和编码方面的学习非常出色,以解决本周在Apple的Learn to Code 2 Swift游乐场中的难题课程。 我很高兴教这些课程,因为我记得我在学习编码时发现参数对于编写简洁的代码有多么强大和有用。 在我们的Swift编码课程中,作为常规课程的一部分,我将为学生提供AirPlay操场,以便我们讨论该学生如何解决Swift操场难题。 之所以这样做,是因为我不断地强调,没有一个人会总是拥有所有正确的答案,或者总是拥有最好,最简洁,最具表现力的代码。 因此,我们(包括我)可以通过分析彼此编写的代码来学习一些东西。 学生展示自己的工作所使用的代码和解决问题的策略的剖析是我所拥有的一些最佳可教的时刻。 我认为“在特定位置放置”课程/操场会是一个非常棒的课程,因为它需要将多个参数传递给函数。 我是对的。 正是由于这个原因,这是一个很棒的课程/操场。 这个运动场使学生有机会创建两个功能并使用 world.place 函数传递三个参数: (expert, at Column: Int, row: Int) 这样,学生就可以通过创建一个函数来解决难题,专家可以将其前进,旋转,收集宝石等。创建这些函数后,学生可以用七行代码来解决难题。 这是遵循本课精神的一个典型的,预期的结果。 这是以下典型答案的示例: iPad的Swift Playgrounds:Brian Foutty在Vimeo上的特定位置放置。 但是,我的一位学生Elliot决定采用本课程的目标,即从字面上解决难题,并以尽可能少的代码行来解决难题。 我的许多学生为尽可能有效地解决难题而感到自豪。 Elliot将代码效率的挑战提高到了我未曾想到的水平。 他认为解决难题的最有效方法是使用新的 place 结合新方法 atColumn:和row:参数 将他的expert角色放置在第一个宝石的确切图块上,并让他的专家收集宝石。 然后,他让他的expert角色移至下一颗宝石,并为所有三颗宝石​​重复该过程。 Swift Playgrounds:来自Vimeo的Brian Foutty创意简洁的编码。 Elliot非常迅速地完成了对操场的编码,并向我展示了他的解决方案。 我说:“太棒了!”他使用可用的代码以独特,有效和出乎意料的方式解决了这个问题。 然后,我们的班级能够进行讨论,以满足特定任务的严格要求,并学习编程以解决当前问题,同时使我们的代码具有足够的通用性,以用于其他游乐场或场合。 我认为Elliot的回答不会被创建该游乐场的Apple团队预期为可能的解决方案。 但是,与青少年一起工作通常会为成年人提供一种独特的方式来研究问题以及如何解决问题。 然后,作为教育工作者的任务是确保学生理解,无论他们多么聪明,简洁和有趣,您都无法通过捷径来解决所有问题(无论是否编码)。 注意:以下是一个截屏演示视频,向您展示如何在Swift Playgrounds应用中记录屏幕。 来自Vimeo的Brian Foutty的Swift Playgrounds屏幕录制。 最初发布在iFoutty.com — Swift Teacher

使用Swift在BST中进行级别订单遍历

开始之前,让我们先回顾一下… 在Swift中使用数据结构 因此,基本上我们已经学习了数据结构并在C / C ++中实现。 在这个故事中,您将看到学习一些基本数据的方法。 Swift中的二叉搜索树 从以前的帖子开始:https: //medium.com/@abhishekthaplithapliyal/playing-with-data-structure-in-swift-ccd8efca9611 medium.com 从最近的两个故事中,我们可以获得一些信息。 关于堆栈和树木。 让我们将它们放到一个新的水平,并结束本系列的其他内容。 此处节点1的级别为1,节点2和3的级别为2,节点4,5,6和7的级别为3。 现在,在进行级别顺序遍历的情况下,从根节点开始,从左到右逐一遍历每个级别。 如下所示 所以最终的内联输出就像 20、9、49、5、12、23、52、15、50 就像我们从左到右逐行编写。 那么,遍历为何排队的背后的策略是什么? 在这种情况下,队列是遍历的最简单方法。 与在队列中一样,操作以FIFO方式进行,即首先进行优先操作,并且在进行层顺序遍历时,我们需要首先访问根节点及其子节点,依此类推。 队列 让我们简要介绍一下队列。 队列具有类似数组的结构,其中元素是从后面添加的,因此操作称为Enqueue ,元素是从前面删除的,称为Dequeue 。 这就像售票柜台中的一条线,在该行的最后一行添加了新人,而票证则被卖给该行的第一人。 太好了! BST就在我这边。 希望你喜欢。 直到那时 快乐—编码😄😄!!!