Tag: swift

在AWS上部署服务器端Swift

开发完应用程序后,下一步就是将其提供给您的受众群体使用……因此,自然的愿望是将其部署到服务器上。 尽管可以将Swift应用程序部署到任何Ubuntu 16服务器,但在本文中,我将重点介绍如何使用Perfect Assistant部署到AWS实例。 如果要遵循,则需要满足三个先决条件:Perfect Assistant应用程序,Mac上可运行的Docker应用程序以及一个AWS账户。 AWS设置 从AWS收集的一些信息: 存取金钥ID和机密 公钥/私钥对 安全小组 访问密钥和秘密 创建新的访问密钥和机密的步骤: 访问https://console.aws.amazon.com/iam/ 从侧面导航中选择“用户” 如果您没有IAM用户,请创建一个,确保添加“程序访问”复选框,然后单击“直接附加现有策略”,然后选择“ AmazonAPIGatewayInvokeFullAccess和AmazonEC2FullAccess”属性。 这将创建一个具有密钥和机密的新用户帐户。 记下它们! 如果您已经拥有IAM用户帐户,请选择所需用户的名称,然后选择“安全凭据”选项卡。 单击“创建访问密钥”按钮,并记录密钥的ID和秘密。 公钥/私钥对 接下来,我们要创建一个新的公钥/私钥对。 转到“ EC2”部分,在导航中单击“密钥对”,然后单击“创建密钥对”按钮。 确保下载后! 将下载的文件(以“ .pem”结尾)放入“〜/ .ssh /”。 这使使用SSH连接到远程系统的应用程序(例如助手)可以访问它。 安全组 接下来,单击导航中的“安全组”,然后单击“创建安全组”。 给您的新组一个简短的名称和描述,然后选择“入站”选项卡,单击“添加规则”。 对于本演示,我建议您添加端口8181并在源下拉列表中选择“ Anywhere”,并确保您从当前IP地址添加SSH访问。 配置完美助手 单击“确定”,返回至Perfect Assistant,在“欢迎”屏幕上,单击EC2框中的“配置EC2凭据”按钮。 这将打开一个新窗口,您可以在其中添加新的凭据。 单击“创建”,为您的新凭证设置命名,然后输入我们从AWS获得的访问密钥和机密。 “区域”应该是您设置的在地理位置上接近您或大多数受众的地方。 按“保存”将锁定配置。 设置演示应用程序以进行部署 接下来,让我们从GitHub上获取“ Perfect App Template”。 仍在“欢迎”屏幕中,单击“创建新项目”,“自定义存储库URL”。 单击位置旁边的“浏览”,然后为模板找到URL,然后粘贴模板的URL:“ https://github.com/PerfectlySoft/PerfectAppTemplate.git” 保留“将Linux构建与Xcode项目集成”的复选框,因为我们在此阶段的目标是Linux部署。 单击“保存”后,系统将启动它是macOS端项目的初始克隆。 进行Linux构建非常简单,只需单击“ BUILD:Linux”按钮。 […]

iOS快照测试

为iOS应用程序的用户界面编写测试非常麻烦。 由于进行基于视图的测试很困难,许多人不愿编写这些测试。 不幸的是,直到最近我还是遇到了验证我的观点的不同状态的问题。 为了实际查看结果,我需要在修改视图后多次运行该应用程序,这花费了很多时间。 因此,我试图寻求一种更有效的方式来处理这种情况,并且找到了一个完美的解决方案— FBSnapshotTestCase 。 它能做什么 快照测试用例采用已配置的UIView,并将其呈现为其内容的图像快照。 它将快照与存储在我的源代码存储库中的参考图像进行比较,如果两个图像不匹配,它将创建另一个参考图像。 通过将视图和现有快照都绘制到两个CGContextRef ,并使用C函数memcmp()对它们进行内存比较,进行比较。 这使其非常快。 安装与设置 按照他们在GitHub页面上的说明,我将pod ‘FBSnapshotTestCase’添加到pod ‘FBSnapshotTestCase’的测试目标中。 另外,推荐的设置参考目录的方法是在我的方案中定义FB_REFERENCE_IMAGE_DIR 。 这应该指向我要存储参考图像的目录。 示例值为$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages 。 很方便吧? 让我们开始编写一些代码。 实作 为了演示如何利用FBSnapshotTestCase的优势,我创建了一个具有两种不同状态的简单视图控制器:空和正常。 一方面,当视图控制器的状态设置为空时,它应该显示一个文本标签。 另一方面,视图控制器在状态正常时应显示字符串列表。 enum State { case empty case normal([String]) } 让我们编写一些测试来验证它们。 首先,子类FBSnapshotTestCase而不是XCTestCase。 然后将recordMode = true添加到setup方法中。 它将使宏记录新的屏幕截图,而不是对照参考图像检查结果。 最后,添加以下两个测试功能,以存储我的视图控制器的图像并运行测试。 func testViewControllerEmpty() { let vc = ViewController() FBSnapshotVerifyView(vc.view) } func testViewControllerNormal() { […]

#3 iOS —重塑视图控制器导航

注意:此屏幕快照中定义的域将无法使用,因为它不会返回 与您的团队ID相匹配的 正确的 apple-app-site-association 文件。 您必须配置自己的域,并确保 apple-app-site-association 文件在网络上可用。 用例 应用程序具有一个可以接收UIColor视图控制器ColorViewController ,并且具有颜色选择器,该颜色选择器触发导航到相同的视图控制器类型,并将所选颜色作为数据传递给新实例。 应用程序可以打开一个深链接URL,该URL的路径中包含十六进制字符串。 应用程序应将十六进制字符串映射到UIColor并将其传递给ColorViewController 。 应用程序应使用以下URL格式打开ColorViewController ,并在背景中显示适当的颜色: https:// DOMAIN / color / COLOR_HEX_STRING http:// DOMAIN / colour / COLOR_HEX_STRING https:// DOMAIN / color / COLOR_HEX_STRING http:// DOMAIN / colour / COLOR_HEX_STRING 目的地 它不过是一个简单的视图控制器包装器,它提供了一些附加功能并简化了截断数据(从URL提取的数据)的填充。 Destination的resolve方法是将URL中的参数映射到目的地视图控制器可以接收的数据的地方。 此类目的地需要与URL模式字符串一起注册。 这些用于CoreNavigation的路由匹配机制。 应用委托 注意AppDelegate类中的registerRoutes()方法。 它说任何与传递的数组中的任何字符串匹配的URL都应解析为Color目标类型。 以:冒号)字符开头的所有参数占位符将替换为从URL提取的数据,并传递给Color的resolove(context:)方法。 定义参数占位符的格式: :PARAMETER_NAME 要么 :PARAMETER_NAME(REGEX_MATCH_PATTERN) 访问提取的参数: 让parameter […]

您了解Swift中的延期吗?

几周前,我开始研究Golang,因为在Axiom Zen中我们已经使用了很多,而且我意识到它还使用了与Swift中基本相同的defer语句。 有趣的是,当我学习堆叠延迟时,我不得不停下来问自己。 Swift中的输出是什么? func some() { for i in 0..<10 { defer { print(i) } } } 由于Golang的延迟使用了堆栈,因此Go中的输出为9,8,7 9, 8, 7, …, 0 。 斯威夫特呢? 好吧,斯威夫特打印0, 1, 2, …, 9 。 因此,Swift使用队列,对吗? 错误! Swift中的defer也使用堆栈,但是defer语句的工作方式是指当前作用域 ,即,它仅在示例中的for范围内进行延迟。 每次通过for循环时,都会弹出defer堆栈 ,这就是为什么它以升序打印数字的原因。 如果是: func someOther() { defer { print(“a”) } defer { print(“b”) } } 正如我所期望b, a那样b, a这将堆叠延迟并仅打印b, a […]

Swift Playgrounds Study:第23天

结果:『Learn to Code2』 数组 ,Island Builder。 我花了两天时间才能完成任务“ Island Builder” 。 对我来说,这是艰巨的任务。 我的解决方案在这里💁 让allCoordinates = world.allPossibleCoordinates //创建两个[Coordinate]类型的空数组。 var岛:[坐标] = [] var sea:[坐标] = [] 用于所有坐标{ 如果坐标列 3 &&坐标行 3 { //附加到孤岛数组。 island.append(坐标) 如果coordinate.column 3 || ordinate.row 3 { //附加到海数组。 sea.append(坐标) } } //对于岛阵列,放置块。 用于岛屿{ world.place(Block(),at:坐标) } //对于您的海浪,放置水。 用于海上{ world.removeItems(at:坐标) world.place(Water(),at:坐标) } 实际上,我放弃了解决任务。 但是,在此任务中我们看不到提供的解决方案。 所以我只需要继续工作。 数组区域很难。

使用Swift创建一个iMessage应用

默认情况下,该示例包含一个“ Hello,World” Label 。 打开MainInterface.storyboard并删除标签。 然后,将其替换为Button ,并将文本设置为“发送本地时间”。 接下来,让该按钮在被点击时执行某些操作。 按住Control键并从按钮将其拖动到MessagesViewController.swift中的类声明下方。 在弹出的对话框中,将类型更改为IBAction并将函数名称设置为sendTime 。 当您在iMessage应用程序中点击“发送本地时间”按钮时,将调用此功能。 日期和时间使用DateFormatter确定。 添加代码以找出当前时间,然后将其发送给收件人。 添加代码后, sendTime函数应如下所示: 当您点击“发送本地时间”按钮时,将调用sendTime函数。 此功能确定本地日期和时间,并将其发送到当前对话。 这就是编写iMessage应用程序所需的全部。 您无需附带完整的iOS应用。 我可以使用TestFlight以及通过AppStore分发扩展。 现在,只要有人在iMessage对话中问“现在几点”,您和我都可以通过单击按钮来提供特定于标准的响应。

Swift 3中的初始化剖析

具有编程经验的软件开发人员应了解什么是“初始化”。 简而言之,这是在使用类或结构的实例之前涉及的一个过程。 在Swift中,这同样适用于枚举。 我浏览了有关初始化的Apple文档,https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html,并意识到Swift中有几个主要且有趣的功能值得分享,这最终促使我撰写了一篇主题相似的文章,但提供了有关每个主要功能的工作方式的更多示例。 但是,本文没有介绍与枚举有关的初始化概念。 本文旨在为我自己的学习提供参考,并希望与其他Swift开发人员分享“ Swift Initialization”。 在整个文章中,请始终阅读嵌入式屏幕截图中的绿色注释。 默认初始化程序和成员初始化程序 默认的初始值设定项是由类和结构自动引入的初始值设定项。 逐成员初始化器仅适用于结构,并且是默认初始化器的另一种形式。 默认初始化程序在类和结构之间的工作略有不同。 如果未定义自定义初始化 程序,则结构类型会自动提供成员初始化 程序 。 类类型没有。 成员级初始化程序采用所有存储的属性,并将其作为初始化程序的参数。 不管存储的属性是否默认为初始值,都以结构类型提供成员初始化程序 。 但是,当存储的属性具有默认值和没有默认值时,它的行为会有所不同。 在结构中,如果存储的属性在定义时默认使用值 ,并且未提供自定义初始化程序,则结构会自动引入两个初始化程序,即不带参数的默认初始化程序和逐成员初始化程序 。 但是,如果存储的属性在定义时没有默认值,则仅引入成员初始化器。 在下面的示例中, let car1 = Car()将触发编译异常。 自定义初始化 自定义初始化程序是开发人员在Swift中创建类或结构时定义的初始化程序。 定义自定义初始化程序后,将没有默认的无参数初始化程序或逐成员初始化程序 (如果它是结构)。 但是,如果我们希望使用默认的初始化器和成员初始化器以及我们自己的自定义初始化器来初始化结构,则可以在extension中编写自定义初始化器 。 请参阅以下部分以获取更多信息。 通过Swift扩展自定义初始化程序 扩展可以向现有类型添加新的便捷初始化程序 ,但不能指定初始值设定项 。 在structure中 ,如果存储的属性在定义时默认为值 ,并且未提供自定义初始化程序,则结构会自动引入两个初始化程序, 默认为无参数初始化程序和逐成员初始化程序,我们可以从中调用这两个初始化程序中的任何一个在扩展程序的初始化程序中。 初始化参数和参数标签 初始化参数可以具有用于初始化程序主体的参数名称 ,以及用于调用初始化程序时的可选 参数标签 。 但是,在定义初始值设定项的参数时使用_(下划线)符号时, 参数标签是可选的。 下面的代码显示了两个带有第二个初始化程序的初始化程序,这些初始化程序无需调用参数标签即可调用该初始化程序。 值类型的初始化程序委托(结构,枚举) […]

创建ReactiveSwiftRealm-第2部分

在第1部分中,我解释了如何创建与Carthage,Cocoapods和子模块兼容的基础项目。 现在是时候编写代码了。 在最初的帖子中,关于合并ReactiveSwift和Realm的过程中,我解释了我想要获得的东西,这是第一步。 我想要一个围绕Realm基本操作的反应式包装器。 让我们从添加操作开始。 我是TDD的忠实拥护者,所以我将从Realm add操作开始在这里应用它。 在测试之前,我们应该将在主要目标上拥有的相同链接框架添加到测试目标。 如果我们不这样做,将会得到奇怪的Xcode错误。 我只需要围绕该简单任务的反应式包装,以便可以在反应式上下文中轻松使用它。 我最需要的是什么? 一个保存方法,该方法返回SignalProducer 为了测试我需要 调用某些东西,它应该返回SignalProducer 我的测试结束是这样的: 当然,它会失败,这是我应该在TDD中期望的(现在看起来很愚蠢,但是由于代码库很大,您可能会编写测试代码,并且在您期望测试失败时第一次通过测试。看到测试失败也是重要),因此请对其进行修复,使其通过测试(仅此而已)。 在ReactiveSwiftRealm组中,我将创建一个ReactiveSwiftRealm.swift文件,其中包含通过测试所需的代码: 导入ReactiveSwift 导入结果 func add()-> SignalProducer { 返回SignalProducer(值:()) } 我需要一个函数来返回SignalProducer,这就是我得到的。 现在,我必须在测试中导入ReactiveSwift和Result,以便它知道什么是SignalProducer,然后运行测试。 通过第一个测试,我必须考虑我需要的下一个功能。 SignalProducer应该保存一个Realm对象 好的,因此我需要保存对象,并且需要添加功能来获取该对象并将其保存。 让我们编写测试代码! 好的,再次失败,正如预期的那样。 (是的,您可以庆祝某些事情行不通)。 让我们修复它: 导入RealmSwift 按照Realm步骤创建FakeObject类 FakeObject类:Object { 动态var id =“” } 更改添加函数,使其带有对象类型参数(您也需要在添加声明文件中导入RealmSwift) 现在,我们将看到我们的第一个测试失败,我们已经更改了函数声明,因此可以预期会失败。 只需对其进行更改,使其也需要一个伪造的对象。 现在我们的第二项测试失败了。 为什么? 好吧,它什么都不保存,所以让我们更改add函数,以便保存对象。 我们将在这里找到并发布,我们需要一个领域参考才能将该对象存储在数据库中。 好的,让我们在add函数中添加一个realm参数,以便我们可以在内部使用它。 当然,由于我们再次更改了功能,两项测试都将失败。 由于我们在两个测试中都需要一个领域实例,因此我将在ReactiveSwiftRealmTest级别上创建它,以便可以在任何测试中使用它。 我将使用领域测试功能,该功能允许我使用内存中领域(而不是真实的数据库): 覆盖func setUp(){ […]

Swift —测试驱动开发(TDD)

本文是同时介绍TDD和多个CI概念的指南的一部分。 您可以在 此处 查看介绍性文章 。 代码测试是开发中至关重要的部分,以确保您编写的代码既可以执行预期的工作,又可以确保将来的更改不会破坏过去的工作(眨眼眨眼的持续集成)。 TDD,即测试驱动开发,它不仅是一个时髦的词,而且是一种非常有趣且易于使用的开发方法。 有了它,您应该首先编写测试,然后再编写使它们通过的代码: 编写测试(该测试将失败,因为您还没有代码!) 编写最少的代码以使测试通过 进一步增强您刚才编写的代码的测试 重构代码以使新测试通过 在添加测试和重构代码之间进行迭代,直到达到所需的功能和代码质量为止。 为了向自己介绍TDD方法,我遵循了Yvette Cook的TDD指南,因此您应该很清楚地解释该概念,并逐步指导您实施示例项目。 有几个吊舱可以使测试过程更加简化并简化编写测试的任务。 他们是: 快 敏捷 因此,接下来,我将展示您可以对它们进行哪些使用: 将两个Pod导入到项目中: 2.从以下位置更改标题: 至 3.代码在spec()函数中运行: 4.用beforeEach块替换setUp()块: 5.使用Nimble,我们可以使用更易于阅读的方法编写测试。 例如: 变成: Nimble不仅易于编写,而且还赋予您更多表达结果的自由,并且还建立在其他XCTAssert功能的基础上(例如,在测试网络请求时,指定异步期望非常简单)。 请查看Nimble的文档以获取更多信息。 您可以在下面找到进一步的比较: 而旧的(如果失败的话)将不会显示文本错误消息(除非我们指定自定义消息,例如XCTAssert(1 == 2, “your custom error message here”) ,它会采用Nimble方法,它将自动使用在it(“message”)标头中指定的描述。 通过使用这些Pod,我认为我的测试不仅易于编写,而且最终也易于阅读(因此,将来可以根据需要进行更新)。 我打算在我现在开始使用的另外两个Pod上写一篇单独的文章,使您可以用更少的代码以不同的方式测试UI🙂现在,您可以检查他们的github页面: 敏捷快照 KIF 确立了测试的重要性之后,接下来的系列文章现在将重点介绍CI方法:它的重要性以及如何在XCode,Swift项目中将其付诸实践。 在这里检查。

快速成功枚举

让我们谈谈Swift中的错误处理。 如果您已经使用Swift一段时间了,那么应该想到两件事。 可选和try-catch块 。 他们为我们提供了很好的服务,并将继续这样做,但是让我们看看处理错误的另一种方法。 为什么? Swift的可选类型很棒,但是有一个缺点。 出现问题时,我们不会收到错误消息。 这很糟糕,因为当涉及到我们要通过UI向用户报告操作失败的原因时,我们不得不说“由于n​​il而失败” 枚举怎么样? 因此,为了捕获可能的错误,我们希望我们的故障函数返回结果或ErrorType 。 那么,为什么不返回枚举而不是返回“ Optional(Result)”呢? 借助Swift的枚举具有关联值的能力,我们可以做这样的事情来保留有关出了什么问题的信息。 在这里,我们可以看到找不到Stevie的信息,并且已将其正确报告给我们的用户。 这比仅对可选选项执行if let / guard并在发生错误时返回null值要好得多。