何番煎じだよって感じですが,アーキテクチャに対する考チャに対する方は割と正解がなくて,自分の中に一つ落とし込んでおいて损はないと感じたため,补充という形で记事にさせていただきます。 アーキテクチャとは? 一言でいうと, アプリケーションを绮丽丽装するための设计方法! アーキテクチャを考虑しない设计でコードを书いていると以下のようなスにぶち当たります。 一つのクラスの肥大化(iOSで言うところのFatViewController) ロジックが烦雑になる 同じ处理を使い回せない チーム开発で役割分担しにくい テストがしにくい 属人化が进み,引き継ぎが难しくなる 机能の追加,修正が困难 等等… 正直まだまだあるとは思いますが,とにかく设计はこだわってないと后で地狱を见るということさえ伝わればOKです。 示例应用 アーキテクチャを语る上で叩き台にするアプリがいるなーと思ったので作りました。 阅覧するときは,见たいアーキテクチャのチャランチ(master / mvc / mvp / mvvm / clean-architecture / clearn-architecture + mvvm)に切り変えてください。 https://github.com/rockname/ArchitectureSampleWithFirebase Firebaseでユーザーの登录/登录,投稿のCRUD处理をする,ものすごくシンプルなアプリです。 FatViewController ブアーキテクチャのない世界をみなさんにはお见せしましょう。(ブランチはmasterです) 投稿一覧シーンであるListViewControllerを见てもらうとわかりますが,こんなに単纯なアプリにもかかわらずすでにコードが123行あります。 ViewControllerがすべての役割を担わされていることがわかりますね。 非常に胖な状态です。 役割 ViewController UIのレイアウト UIの更新 ユーザーのアクション通知 データの处理 データの更新通知 ビジネスロジック 评価 いいところ🙆 思考停止でコーディングできる(これはいいところなのか…?) UIKitの恩恵を最大に享受できる 悪いところ🙅 それ以外すべて 模型视图控制器(MVC) Webアプリケーションフレームワークでよく闻くやつですね。 Appleの公式ドキュメントでもiOSアプリ开発はMVCが一般的みたいな书き方がされています。 https://developer.apple.com/jp/documentation/CocoaEncyclopedia.pdf しかし,iOSのUIフレームワークであるUIKitはViewとControllerが密接に系がっており(ViewControllerというクラスがあるくらい),iOSのMVCはよくMassiveViewControllerだなんて皮肉を言われています。。 […]
这一次,我们将讨论flatMap方法。 但是首先让我们考虑一下上下文。 假设我们有一个数组数组: var arrayOfArrays = [ [1, 1], [2, 2], [3, 3] ] 将其内容乘以2是一个挑战,其结果应如下所示: // [[2,2],[4,4],[6,6]] 解决此难题的一种方法可能是两次使用map Array的方法,如下所示: //首先迭代数组的数组 arrayOfArrays。 映射 {数组在 //和第二次迭代 //当前数组 返回数组。 映射 {中的整数 //将其内容乘以2 返回整数* 2 } } // [[2,2],[4,4],[6,6]] 好的,接下来是一个新的挑战,将乘法数组转换为仅一个数组,如下所示: // [2,2,4,4,6,6] 幸运的是Array的结构为此目的有一个称为joined ,让我们使用它: var multipliedByTwo = arrayOfArrays。 映射 {数组在 返回数组。 映射 {中的整数 返回整数* 2 } } var flattened […]
在这里,您将看到如何使用Swift 3.0为iOS构建一个简单的计时器。 我假设您对Swift编程语言,Xcode和Storyboard有基本的了解。 如果您需要基础知识方面的帮助或在情节 提要中 设置UI,请访问 www.raywenderlich.com, 以获得一些很棒的初学者教程。 计时器类 我们将使用Apple提供的Timer类。 在文档中定义了一个计时器,如下所示: “计时器等待直到经过一定的时间间隔,然后触发,将指定的消息发送到目标对象。” “例如,您可以创建一个 Timer 对象, 该 对象将消息发送到窗口,告诉窗口在一定时间间隔后进行更新。” 创建Timer类的目的是使它易于在特定时间触发动作(例如更新标签或触发方法)。 建立计时器 创建一个新的“ Single View Application”,为其命名,并将语言设置为Swift。 在情节提要中新建一个视图控制器,或使用预先存在的默认视图控制器。 添加标签。 (此标签将显示开始时间以及以秒,分钟和小时为单位的倒计时。) 添加三个按钮:“开始”,“暂停”和“重置”。 我的初始设置如下: 注意:在标签中设置为占位符文本的内容无关紧要,因为我们将在代码中提供标签文本。 我使它看起来像一个计时器,但它的工作原理与“标签”一词一样好。 但是,您为标签设置的字体将在程序运行时显示。 我选择Courier New,因为它是等距的(所有字母/数字都相同的宽度),并且不会随着数字递减而四处移动。 3.将标签和按钮从情节提要板连接到视图控制器类。 快捷方式:要从Storyboard中的助手编辑器中打开View Controller文件,请按住Option,然后在左侧的Navigation inspector / menu中单击类文件。 我假设您知道如何将标签和按钮连接到适当的类。 4.接下来离开情节提要,转到“视图控制器”类。 在timerLabel出口下,创建以下变量: var seconds = 60 //此变量将保留秒的起始值。 它可以是大于0的任何数量。 var timer = Timer() var isTimerRunning = […]
从来没有比现在更好的时间成为应用程序开发人员。 随着网站越来越多,过时的公司正在从Web切换到应用程序,并且此过程才刚刚开始。 苹果公司在2014年首次推出的Swift语言已成为世界上最重要的编程语言之一。 使这种语言如此流行的原因是,正确教授它非常容易学习。 这就是为什么在选择有关该语言的在线课程时需要仔细选择的原因。 大多数课程都以“创建Instagram”或“制作自己的Facebook,Snapchat等”之类的承诺使学生蒙蔽,这是荒谬的。 坦率地说,无论老师多么出色,都不可能创建一个可以让数百人在几个月内,数小时内使用它的应用程序。 但是我必须承认我也信守了那些诺言,这就是为什么我知道它们是错误的。 尽管您可能会以流行的应用程序的较差版本结尾,但是您对应用程序或编程语言的工作方式一无所知。 您将无法使用这些克隆中的任何一个来增强您的履历,因为您将无法向任何人解释代码为何起作用,因为您所做的只是复制并粘贴了教师告诉您的内容。 这就是为什么我们在RUME学院决定现在是时候创建自己的语言课程了。 我与同事Johannes Ruof一起教的课程非常适合希望开始学习如何使您的应用创意成为现实的每个人。 我们涵盖了该语言的所有重要方面,即使您是初学者,我们的教学方法也包含帮助您理解它的实际示例。 我们已经培训了7500多名学生,并使数百人以Swift开发人员的身份开始了自己的事业。 一旦成为开发人员,就有许多工作机会在等待着您。 无论您是选择在公司工作,是自由职业者,还是想创建自己的应用程序并使您的想法成真。 Swift被认为是初学者最简单的编程语言之一,因为它很容易理解和应用。 它是用于开发iOS和MacOS应用程序的语言。 有可靠的谣言称,谷歌也在考虑将Swift用作Android的首选编程语言。 我们的课程是作为iOS开发人员成功事业的完美起点,为了使您更轻松地做出决定,我们为所有阅读本文的人提供92%的折扣。 只需点击此课程链接即可 或在udemy上使用代码:MEDIUM15。
几周前,苹果发布了Swift 3.0,对2.3进行了重大改进和改进。 特别是其中一项更改是动词和名词在句法上的区别,以阐明功能中结果的状态,例如: sort()与sorted() 枚举()与枚举() reverse()vs. reversed() 总结一下:名词以-d结尾(排序,枚举,反向)将指示对象的新实例,而动词(sort,枚举,反向)描述对对象实例本身所做的更改。 为了更好地理解这种区分可能会有所帮助的特定上下文,我以以下示例为起点。 反转字符串时,请考虑使用反转函数: 上面的代码实质上分为以下步骤: 1.将字符串类型的“单词”分解为字符。 它 以字符集合的形式成为String内容 的 视图 。 2.冲销货款; 现在是Reversed.Collection 3.将反向集合转换为字符串,以便将其作为新变量传递 4.返回包含反向字符串值的新变量 请注意第4点-整个过程将返回一个全新的String,该字符串与原始“单词”字符串无关。 但是,如果我想逆转单词本身怎么办? 在更改String实例时,由于String在Swift中是Struct的现有类型,因此无法访问Struct来添加新方法并更改该实例的值。 在这种特殊情况下, 扩展的使用成为String附加功能(可以更改其实例值)的唯一选择。 函数通常可以通过两种方式对实例变量进行更改:要么有一个全新的变量具有更改后的状态(该状态由函数中的返回值指定),要么可以更改实例变量本身。 当以函数语法表示时,将指定关键字“ mutating ”来描述对实例变量本身进行更改的结果。 类似地,字符串的扩展可以通过使一个函数返回新的String以及使另一个函数(“变异函数”)返回实例本身的更改状态,来在实例变量的这两种情况下扩展。 因此,如果我们以某种方式需要其他选项来更改此String的原始值,则可以编写一个扩展程序,其中包含解决两种情况的函数: 请注意,第二个函数是一个变异函数,它不返回 String,而String本身现在是反转的String。 我们可以如下测试该语句: 由于扩展名中的变异函数会更改原始String的值,因此称为reverse()的变异函数表示Swift 3中该动词描述了原始变量的更改状态。 该示例清楚地表明,语法细节可以提高语言的连贯性,并且在String的扩展中使用它可以创建一种语法选项,该选项将两种不同的结果分开:创建对象的新实例以及更改原始值。 向前发展,虽然语法上的这一新变化可能会造成暂时的混乱:例如Swift 2.2中的sort(),该函数用于返回排序后的数组; 和sortInPlace()用于对数组本身进行排序-在Swift 3中,它们现在被sorted()和sort()取代。 总而言之,Swift 3中的这种特殊性是一种优雅简洁的方式,可以促使程序员更加流利。
“泛型编程 是一种 计算机编程 风格, 其中 算法 是根据 类型 编写的 待定,然后 在需要作为 参数 提供的特定类型时实例化。” — Wikipedia 使用泛型编写代码是一种编写函数和数据类型而无需指定需要使用哪种确切类型的方法。 顾名思义,泛型类型不是特定的。 通过使用泛型,我们可以编写非特定的代码,因此,我们可以以更清洁,错误更少的复杂方式抽象代码。 在上一篇文章中,我描述了数组,字典和可选变量是泛型的示例。 在第二部分的文章中,我将讨论编写通用数据类和结构,编写通用函数和约束通用类型。 第三部分将讨论关联类型和通用Where子句。 编写通用数据类和结构 虽然数组,字典和可选变量都是泛型的示例,但我们也可以使用泛型来创建自己的数据类型。 例如,我可以堆一个 具有泛型的数据类型-不特定于任何数据类型(浮点数,双精度数和整数)。 堆栈使用LIFO(后进先出)过程,将新项目推到堆栈顶部,然后从堆栈中取出最新项目。 我喜欢将其视为一叠纸牌,将它们一叠放在另一叠上,并且只能从顶部取出。 假设我要创建自己的堆栈。 我可以使用尖括号将其指定为通用,这意味着,我可以在创建堆栈时决定要堆栈的内容。 在这种情况下,我想编写一堆字符串,这些字符串代表我当前正在阅读的所有编码书。 1:我创建一个结构来表示我的EricasStack数据类型。 请注意,在尖括号之间使用“通用 ”一词。 我可以在那里写任何词(也许是“炸玉米饼”?)作为我在此EricasStack中使用的值的占位符。 2:我创建了一个泛型数组,该泛型将容纳我的编码书籍堆栈。 3: 我想一次将两本书添加到我的书架中,所以我编写了一个推入两个项目的函数。 4:我想一次将两本书移到我的书架中,所以我编写了一个函数,该函数返回要被POPPED的两个项目。 5:我创建一个类型的EricasStack实例。 请注意,我现在只能追加字符串。 我将两本书推到CodingBooksStack上,然后再推两本书(总共四本书)。 然后,我打印出最终的CodingBooksStack包含的内容。 当我调用.popTwoItems()时,还可以看到打印出来的打印内容。 我也可以赚到一笔EricasStack的钱: 如您在上面看到的,当我创建EricasStack类的实例时,可以用任何类型填充。 编写通用函数 假设我想获取一个Int,然后将其复制到数组中。 假设我想获取一个String,然后将其复制到数组中。 假设我想使用Float,然后将其复制到数组中。 我应该为这三种不同的类型编写三种不同的功能吗? 我可以使用GENERICS编写一个仅适用于所有类型的函数。 函数和方法在泛型类型的上下文中可以是泛型的。 1:我编写了一个名为的通用类型的函数,该函数接受一个项目,并指定一个整数,该整数指定要复制ItemToDuplicate的次数。 2:我创建一个空数组来保存我的arrayOfDuplicates。 3:循环numberOfTimes,每个团队都将一个ItemToDuplicate添加到我的arrayOfDuplicates数组中。 […]
放大 作为图灵软件与设计学院的学生,我将大部分时间都花在了Ruby,Rails和JavaScript上。 在图灵的最后一个模块中,向学生展示了Scale Up,学生可以在其中选择从事棕地项目或完成独立学习。 我选择进行独立学习,重点是学习Swift并将我学到的东西纳入一个可敬的项目中。 背景 在图灵的早些时候,我建立了EarlyBird,这是一个在线的发球时间预订系统。 这样,我构建了一个单独的EarlyBird API来提供高尔夫球场数据(名称,地址,电话号码,图像和开球时间)。 我的Scale Up目标是构建一个本地iOS应用程序,以补充我的模块三个项目EarlyBird。 最低可行产品(MVP) 我总是喜欢有一个计划。 因此,我的第一步是确定我认为可以接受的MVP。 我得出结论,我的应用程序应使用Swift完成以下任务: 使用EarlyBird API的高尔夫球场数据 在UITableView中显示高尔夫球场数据 允许用户预订开球时间。 没有此功能,用户将很难理解该应用程序提供的价值。 文档和教程 巩固我的MVP之后,我阅读了一些Swift文档: 快速浏览 UIKit用户界面目录 适用于iOS的View Controller编程指南 该文档使我对Swift的语法和结构有了基本的了解。 接下来,我确定了一个合适的教程。 有很多公司提供Swift教程,但是我进入了Team Treehouse。 该公司很熟悉,并为Swift 2提供了网络编程。这似乎是一个理想的起点。 壁垒 在使用Swift 2完成网络编程时,我发现我在适应新的IDE Xcode时遇到了艰巨的时间。 由于Swift的快速发展,我发现的大多数教程都是在Swift 2的上下文中编写的。但是,对于这个项目,我正在使用Swift 3。并非总是如此。 此外,大多数博客和教程都使用情节提要,交互式生成器和可可豆荚。 我发现每一个都使我感到困惑。 我只是想编写工作代码。 因此,我开始寻找如何以编程方式在Swift中使用API。 最终,我在Swift中找到了Simple REST API调用,并在Swift 3中找到了该教程的更新。这些教程非常了不起。 Grok Swift的Christina Moulton很容易理解,并提供了详尽的例子。 这是导致我的项目取得重大进展的第一个资源。 在她的教程的帮助下,我能够结合所学到的知识来使用EarlyBird API,解析数据并在UITableView中显示课程名称和地址。 结果 我意识到自己已经没时间了,因此需要确定如何满足我最后的MVP要求:允许用户预订开球时间。 […]
我的“部署服务器端Swift”系列文章中的第三篇,现在我将演示如何将服务器端Swift应用程序部署到Digital Ocean Droplet。 如果要遵循,必须满足三个先决条件:Perfect Assistant应用程序,Mac上可运行的Docker应用程序以及Digital Ocean帐户。 服务器设置 第一步将是设置一个新的Digital Ocean Droplet。 在Digital Ocean控制台中,单击“创建液滴”按钮。 选择Ubuntu 16.0.2.x64发行版,所需的大小,数据中心位置以及所需的其他任何特定选项。 您将返回到Droplet列表,其中列出了新的Droplet。 创建完成后,您将看到IP地址。 复制此文件,然后在终端中输入 ssh root @ 您的root密码将到达您的电子邮件中,并使用它登录。将立即要求您更改密码-这是一项安全功能,意味着只有现在您知道该密码。 现在我们要安装Swift并安装所有正确的依赖项。 转到https://github.com/PerfectlySoft/Perfect-Ubuntu并复制“ install.sh”的内容 接下来,创建安装文件并对其进行编辑: 触摸install.sh 纳米-w install.sh 将内容粘贴到剪贴板,然后按ctrl-x并保存。 然后我们要使其可执行并运行: chmod + x install.sh ./install.sh-确定 完成此操作后,您的系统将可以使用Swift和Perfect! 编译代码 如果您遵循了《服务器端Swift部署》系列中的上一期文章,则可能会注意到接下来的部分几乎是相同的。 那是因为他们是…… 现在切换到Perfect Assistant,让我们从GitHub获取“ Perfect App Template”。 在“欢迎”屏幕上,单击“创建新项目”,“自定义存储库URL”。 单击位置旁边的“浏览”,然后为模板找到URL,然后粘贴模板的URL:“ https://github.com/PerfectlySoft/PerfectAppTemplate.git” 保留“将Linux构建与Xcode项目集成”的复选框,因为我们在此阶段的目标是Linux部署。 单击“保存”后,系统将启动它是macOS端项目的初始克隆。 进行Linux构建非常简单,只需单击“ BUILD:Linux”按钮。 幕后操作是准备好Docker容器,将项目的依赖项克隆到沙盒位置,并进行沙盒化的Linux构建。 完成后,您应该看到最后三行是这样的: 编译Swift模块’Perfect_App_Template’(10个来源) 链接./.build_lin/release/Perfect-App-Template […]
基本上,单元测试的思想非常简单: 了解输入并将输出与期望值进行比较,我们可以验证黑盒是否正常工作。 + ———————- + 输入| | 输出量 + ———-> +黑匣子+ ————> | | + ———————- + 尽管经常知道单元在您的项目中实现了什么功能,但是对于单元测试环境仍然未知,这就是为什么在这里使用Blackbox术语的原因。 但是什么是单元测试单元? 嗯,有很多定义,但是它们都以一种或另一种方式将Unit定义为功能单元,我想说是不可分割的功能单元 。 在Swift语言中,功能的不可分割的单元是一个功能。 每个函数都可以带有一些参数(输入),可以返回某个值(输出),因此可以通过单元测试来验证其功能。 您可以编写一个涉及整个类型(类或结构)或什至组合成一个模块的几种类型的单元测试,但是: 将一个单元测试与一个功能绑定在一起可以使您的测试尽可能地适应代码。 好的,让我们玩一下Swift编程吧。 因此,当您具有如下方法或函数时,单元测试的想法非常简单: 为了验证它是否正确运行,您编写了一些传递已知Params代码,并检查返回的Result是否与这些参数所期望的一样。 这个特殊的代码称为单元测试,因为它测试一个单元doSomeWork函数。 这是一个精致的示例,在现实世界中, doSomeWork函数而不是Class或Structure的方法,因此其工作可能取决于其他方法和属性。 尽管通常依赖另一种方法并不危险,但是应注意依赖属性和实例变量,因为它们描述了类型的状态并且在测试之间是持久的,此处的规则: 使您的方法成为函数式编程的纯函数 。 纯函数是不依赖所有者状态且不会产生副作用(更改所有者状态)的函数。 像许多其他现代语言一样,Swift也是面向对象的,它具有具有属性和实例变量的类,这使得不可能将所有方法都当作纯函数使用,特别是如果它是UI应用程序。 万一该方法无法重构为纯函数,您的规则是: 尽可能减少方法对其所有者状态的依赖 使用纯函数(除了使代码可测试以外)的另一个有用效果是,它们将函数式编程的优点引入了您的应用程序。 现在可以安全地构建方法链,并且对于相同的输入参数,其结果将始终相同。 它还通过增加可扩展性和减少耦合来改善应用程序体系结构。 回到无法摆脱对状态的依赖的方法,可以依靠的一种提高其可测试性的技术是依赖注入 , 考虑下一节课: 在这里, Jobs将在doSomeWork方法中执行实际工作的Jobs委托给ConcreteWorker ,由于以下原因,我们不能删除使doSomeWork不利于测试的依赖关系: ConcreteWorker可能依赖于在测试过程中难以设置或无法设置的环境,例如,它可能会使用Simulator无法使用的iOS功能 Jobs可以开始使用ConcreteWorker的子类来覆盖work(:)方法,或者甚至可以在运行时选择适当的工作器 这些是以下事实的结果: Jobs控制了ConcreteWorker实例,而无法从外部进行管理。 为了解决这个问题,我们将使用依赖注入来反转此控件: 请注意,我们还引入了Worker协议,该协议为Jobs使用的工人定义了一个合同,该合同将其与具体的worker实施分离。 单元测试还有另一条规则: 将测试与测试的类隔离开 […]
在最后三个会话中,我们在示例代码中添加了背景跟踪引擎+地图绘制。 使用示例应用程序进行短期运行会使您感到它已经像Runtastic这样的正常运行应用程序一样工作。 但是,您可能会遇到一些应用无法正常运行的情况。 尤其是在跑步时.. 在多云的天气下 在被高楼大厦包围的小巷里 在一个有许多树木的森林或公园里 为了在这种情况下使您的应用像Nike +一样更准确地工作,您需要将应用日志设置为“仅限好位置” 。 在这篇博客文章中,我将解释如何制作各种过滤器以仅记录良好的位置。 记录准确的位置不仅可以帮助应用程序不仅在地图上绘制漂亮的路径,而且还可以从这些位置计算出准确的距离或速度。 在当前示例中,我们只是将新位置记录到didUpdateLocation回调中的locationDataArray中。 首先,我们将其替换为对filterAndAddLocation()的调用,如下所示。 左侧轨道(不带过滤器)已在标有蓝色圆圈的区域周围记录了几个不正确的位置。 正确的轨道没有不正确的位置,路径看起来更平滑。 比耐克+更好 我使用过滤器测试了示例应用程序,并将其与Nike +的性能进行了比较。 我在iPhone上同时打开了示例应用程序和Nike +,然后跑了2–3公里。 在标有蓝色圆圈的区域,我们的跟踪算法显示出更好的性能。 后来有一天,我在涩谷的街道上奔跑。 Nike +和我们的示例应用程序的跟踪路径如下。 这两个试验还不足以称为实验,但是我上面解释的过滤器似乎使我们的应用程序具有与Nike +相同甚至更好的性能。 更好的跟踪引擎 还有一些空间可以使此跟踪引擎变得更好。 如果您在iPhone放在背包里的大雨天里奔跑在森林中,则可能看不到您的应用程序跟踪任何内容。 如果您看到这种情况,则说明您的过滤条件可能太严格了。 使跟踪引擎更强大的最后几个步骤是使您的过滤器适应环境。 我不会对此做更深入的介绍,但是这里有一些提示 从平均水平精度知道条件 从位置回调之间的时间间隔了解条件 知道天气 迎接挑战,使您的引擎变得更大!