简介: 在本文中,我们将分四个部分逐步构建您的第一个Set应用程序。 第一部分将向您介绍MVVM应用程序体系结构。 第二部分将演示SetSDK设置过程。 第三部分将应用MVVM概念来为您的应用程序创建支架。 最后,在第四部分中,我们将使用SetSDK全天实时显示出发地和预计的目的地。 可以从Set Gitlab存储库下载该项目的源代码。 Set SDK允许任何开发人员通过简单的pod install将机器学习和用户行为预测集成到他们自己的应用程序中。 SDK的第一个版本侧重于用户位置,回答了以下问题:他们现在在哪里,下一步要去哪里? 我想提供一个简单的演示应用程序,以演示如何将SDK集成到您自己的项目中以及如何使用SDK的某些功能。 在我讲的时候,我将使用Apple的MVC(模型视图控制器)体系结构,MVVM(模型视图视图模型)和一种启用MVVM的技术(称为RxSwift)来替代它。 第一部分:MVVM概述 关于MVC设计模式为何变得令人头疼的信息很多,尤其是在更复杂的应用程序中。 MVC对视图控制器负有太多责任。 关注点很少。 在下图中,您将看到视图和模型主要只是存在而无需做任何事情,而视图控制器则负责更新和接收来自模型和视图的更新以及所有业务逻辑,数据库访问,联网等。 在复杂的应用程序中,视图控制器可能会增长为成千上万行代码,并且很难维护。 MVVM是对MVC的简单添加,它简化了视图控制器的作用: 对于您应用中的每个屏幕或视图控制器,我们都会引入一个附加文件,即视图模型。 视图模型负责与模型数据进行交互,并将业务逻辑和显示格式应用于该数据。 视图模型还可以利用数据库或网络抽象。 格式化的数据通常通过简单的属性,RxSwift Observable或类似的技术(稍后会详细介绍)提供给应用程序的视图层。 视图控制器的新角色是通常使用RxSwift之类的工具简单地将视图模型公开的数据“绑定”到视图。 视图控制器还处理诸如按钮轻击和手势之类的用户交互,将这些事件通知视图模型。 这样,视图和视图模型紧密耦合,可以视为单个功能单元。 MVVM可以使关注点更加清晰。 它从视图层中删除了业务逻辑和数据格式,并创建了易于通过单元测试进行测试的视图模型。 可以以“无头”方式(没有任何视图)测试许多应用程序,而可以使用更合适的工具(例如Xcode UI测试)来测试视图。 这样就导致了具有更少错误的应用程序,更易于维护。 第二部分 启动SetSDK应用 要启动SetSDK,您将需要应用程序的客户端凭据。 我们目前正在使用一个自助服务开发人员门户网站,您可以在其中创建这些凭据,但是现在发送电子邮件至sander@set.gl,您将通过电子邮件接收凭据。 SetSDK使用Cocoapods分发。 如果您不熟悉它,请访问他们的网站,其中有许多很好的入门指南。 使用File > New > Project… > Single View Application创建一个新的Xcode项目。 我叫我的MVVMSetSDK。 创建项目后,将其关闭并在命令行上导航到项目的根目录。 通过运行pod init初始化Cocoapods。 打开新创建的Podfile进行编辑,并向其中添加SetSDK依赖项: 并提供当我们要求使用他们的位置和运动数据时显示给用户的Info.plist字符串。 […]
介绍 枚举(Enum)为一组相关值定义一种通用类型,并使您能够在代码中以类型安全的方式使用这些值。 假设我们有一个名为dayType的方法,该方法接受一周中的任何一天,然后返回Weekend为Saturday and Sunday , Weekday为Monday, Tuesday, Wednessday, Thursday and Friday并返回This is not a valid date因为它无法识别已通过的内容进去。 该函数将按方面工作,但是当您实际要传递friday ,即使我们实际上要键入的是friday您误输入了friday时会发生什么。 上面的开关转到默认值。 This is not a valid date 。 这就是类型安全的enum带入表中。 它通过为一组相关值提供通用类型来帮助我们避免此类风险,如下所示: 通过定义用于保存日期的枚举,我们已经能够消除String的使用。 我们不需要在switch语句中的day枚举的每个声明之前使用Day追加,因为我们已经将day分配为Day类型。 因此,可以将dayType函数简化为以下形式: 我们必须了解,枚举最适合于声明具有有限可能状态的类型,例如方向(北,南,西,东),运动(上,下,左,右)等。 枚举值 我们可以为每个enum案例分配值。 如果enum本身确实与某物有关,则这很有用 我们可以使用rawValue关键字访问分配给枚举的值。 要访问上面的Week枚举,我们可以使用Week.Monday.rawValue ,它将返回Weekday 。 枚举关联值 关联值是将附加信息附加到enum案例的一种绝佳方法。 假设您正在编写交易引擎,则有两种不同的可能的交易类型,即买入和卖出,它们将具有特定的库存和金额。 我们可以使用如下的关联枚举值来表示 枚举方法 我们还可以在如下enum定义方法 注意上面的代码片段,对于enum每种情况,func描述都将返回“ This is a apple device”。 为了避免这种情况,我们可以在以下描述方法中使用switch语句 很高兴与您分享这篇文章。 如果您喜欢本文,请通过鼓掌👏表示支持。 […]
我今天正式开始学习iOS开发的Swift。 几天前,我和妻子阿里斯(Aris)在Barnes and Noble Book Store中选择了一本书。 乍看之下,我大致看了这本书,发现这本书更侧重于Swift编码的基础知识。 在这段时间里,除了BJ Miller撰写的《 24小时学习Swift》这本书外,我别无选择,但是Aris告诉我,我迟早要学习基础知识。 最后,我同意她的看法,发展是学习新语言的较快方法,但是语法,基本知识是基础,我应该在真正建立基础之前对其进行学习。 在第一个小时,我了解了Swift及其父Objective-C的故事。 而且我已经熟悉本机IDE XCode。 而且,我还会在Playground和REPL上玩耍,这是XCode提供的两个功能,用于测试整个项目的部分代码。 使用它们的主要好处是用于任何逻辑,运算等的测试,您无需再次创建独立的项目。 Playground和REPL之间的区别是REPL在终端中运行,只是以“ xcrun swift”开头,而Playground是XCode中的一种文件类型。 另外,我知道Swift中最基本的数据类型之间的区别。 Var —变量,Let —常数。 将int转换为String,使用“ String(a)”,合并两个字符串,仅使用“ +”和一些基本的字符串转换方法,“ lowercaseString”和“ uppercaseString”。 无论如何,这是学习Swift的一个很好的开始。 还有很长的路要走,但是我有信心。
在过去的好时光中,过去常常需要花费大量的数学才能产生一种幻觉,即玩家正在向更大的“世界”移动。 我最近一直在玩SpriteKit,今天我了解了使用SKCameraNode实际创建该效果有多么容易。 什么是SKCameraNode 苹果的文档很好地解释了这一点。 SKCameraNode对象用于指定场景中可以从中渲染场景的位置。 换句话说,它可以用于在游戏世界中滚动玩家的视图。 如何使用它 俗话说,一张图片值得一千个字。 通过一个示例,了解SKCameraNode工作方式将更加容易。 我们将建立一个游戏场景,让玩家能够通过点击屏幕来浏览世界。 世界观将始终以主角为中心。 为了给事情增添趣味,我们还将添加一个得分计数器叠加层。 让我们首先使用SpriteKit创建一个新的iOS游戏。 默认项目模板包括带有一些示例行为的GameScene 。 由于我们专注于相机行为,因此我们将从头开始创建自己的SpriteKit Scene 。 让我们在场景编辑器中放置一些Color Sprites : 我将其中一个尺寸缩小(50×50),并给它命名一个名称player ,以后我们可以用它来从代码中引用该对象。 这将是精灵对象,它将响应触摸事件并在世界范围内移动。 我们的“相机”(播放器的视图)将以该对象为中心。 通过足够的拖放操作,让我们打开游戏场景swift文件并开始编写一些代码。 声明类型为SKCameraNode的可选变量: var cam: SKCameraNode? 这将是我们对相机的参考。 场景进入视野后,我们将初始化变量: 覆盖func didMove(以查看:SKView){ super.didMove(查看) cam = SKCameraNode() self.camera =凸轮 self.addChild(cam!) } 这里要注意的重要一点是,相机节点具有自己的框架,该框架占据屏幕的大小。 设置相机效果的位置会转换为设置可见屏幕的中心。 为了演示这一点,让我们首先尝试让我们的“玩家”在屏幕上移动以响应触摸事件。 为此,我们将在场景首次进入视野时获得对玩家对象的引用,并在触摸屏幕后使其移动: var cam:SKCameraNode? var播放器:SKSpriteNode? 覆盖func didMove(以查看:SKView){ super.didMove(查看) cam = SKCameraNode() […]
数学是编程的必要部分。 没有解决的办法。 并非来自数学/科学背景的正在学习编程的人; 但是,那些没有工程学学位的人(提示:我也没有)仍然可以学习编码! 编程所需的数学通常不会超出大多数人所知道的范围。 在Swift中,可以使用几种运算符来执行数学方程式。 在这篇简短的文章中,我们将讨论每个。 配置 首先,如果尚未打开Xcode,请点击Create New Playground 。 给它起一个类似于Math Operators的名称,然后单击Next 。 选择某个位置以保存此.playground文件,然后单击“ Create以保存它。 您应该会看到类似下面的屏幕。 删除左侧的所有样板代码,但根据需要保留import UIKit 。 赋值运算符 就像在数学中使用等号一样,使用赋值运算符(=)来赋值。 在您的游乐场中键入以下示例,以了解其工作原理: 变数3 = 3 当我们创建上述变量并将其命名为three 。 我们将其设置为字面上等于数值3。变量的名称实际上是不相关的。 我们可以给它起任何名字,它仍然可以作为在整个代码中使用值3一种方式。 算术运算符 就像在数学课或图形计算器中一样,在Swift中使用了四个基本算术运算符(+,-,*和/)。 以下是一些示例,向您展示如何在Swift中使用它们。 将以下内容添加到您的游乐场: var product = 10 * 20 //乘法运算符为* var sum = 5 + 6 //加法运算符为+ var Difference = 10 – 3 […]
每月在日本东京附近举行一次名为“ potatotips ”的聚会。 它收集了有关iOS和Andr0id应用程序开发的提示。 第35次聚会在Toreta,Inc.举行。 在2016年11月29日! potatotips#35(iOS / Android开発Tips共有会)(2016/11/29 18:30〜) 开催概要potatotipsは参加者全员がTipsを発表するというコンセプトのiOS / Androidアプリ开発者向けの勉强会です(はオ,最近はオーディエスス枠があります)。今回はトレタさん主催での开催となります。引き続き主催… potatotips.connpass.com 顺便说一下,与会者被分配了以下角色之一: 对iOS或Android开发进行闪电讨论talk 在我们自己的博客上聚集他们✍️ 观众🤔 这一次,我的角色是在自己的博客上收集有关iOS应用程序开发的闪电演讲。 但是,已经有一些用日语写的很棒的博客。 因此,我将介绍活动之后撰写的主题和博客。 注意:其中一些标题由我自行决定是否以英语命名。 对不起,如果我误解了我的翻译。 🙇 关于iOS的主题 @y_koh (y_koh) 在Toreta,Inc.支持Swift 3 通过kumapo 尝试符合MVVM的面向协议的编程 @yimajo ( y.imajo ) 在触摸栏上显示推文的提示 适用于iOS的GitLab CI ( @ikamooon) (いかもん) @TachibanaKaoru (Kaoru)的嵌入式框架的实际应用 Popover通过@hsylife简化了 iPhone / iPad应用程序的开发 流程 @ nafu003 对Firebase的推荐 如何通过@yomoapp 制作UI组件
2015年11月,我踏上了一个激动人心的新旅程,构建一个iOS应用,将iPhone上的图像和视频投射到连接Chromecast的电视上。 在Swift中,作为一个单独的开发人员,作为一个辅助项目,所有这些都在其中。 在这篇文章中,我将分享一些考虑因素和实践,这些因素和实践已帮助我在3.5个月内将代码扩展到4000行以上,同时又将技术负担降至最低,并最大程度地提高了可维护性。 快速预览: 就上下文而言,第一个版本的功能已完成约50%,因此我希望代码库最终会翻倍。 与我以前的所有应用程序和客户端项目相比,我估计在编写更多模块化代码而更少编写模块化代码的同时,我可以更快地增加价值- 至少两倍 。 事不宜迟,这就是我的工作方式: 口头禅:为维护性和未来自我而设计 力争绝不重复代码 始终将源文件保持在200行以下 代码本地化获胜。 凝聚 不要分散属于同一类的多个类代码。 使用类内部的扩展对确实属于一起的功能进行分组。 这使得在需要时更容易将事情排除在外。 适当地命名事物 最小化可变状态 仔细考虑对象图中的所有权 , 尤其是对于异步调用 使用ViewModels驱动UI更新 在添加新功能后始终进行重构 添加新功能后,请务必进行广泛的测试-在添加新代码之前先修复AKA错误 默认将所有内容设为私有 在Interface Builder中完成所有UI和布局。 代码不是您的表示层所属的位置! 错误处理对于应用程序设计至关重要 使错误对开发人员和用户友好 程序员错误应立即消除 奖励 :将开发容器用于我计划开源的自包含代码,例如这样。 到目前为止我还没有做 ReactiveSwift :我很想尝试一下,并在应用程序中利用Observables的功能 ,但是还没有机会。 TDD / BDD /单元测试-尽管我已经对依赖注入进行了仔细的考虑,并且上面的约束迫使我保持班级小。 集成测试。 由于我总是在添加新功能之前修复错误,因此这并不是一个强烈的要求。 但是,我为接收器应用程序构建了一个伪造/存根 ,以便在没有可用的Chromecast设备时可以测试大多数应用程序。 另外,我可以在运行时在假/真实接收器之间切换。 其他注意事项 对于这样的附带项目,我发现尝试每天取得一些进步是有益的,并且如果不进行任何工作 ,通常连续三天不能超过。 这使我始终专注于产品,并且我可以计划新的工作或考虑如何持续解决问题。 在单独构建此文件时,我可以使用一个Google文档来跟踪进度,错误,待办事项,里程碑和日常任务。 在现阶段,我发现这比拥有专用于每种情况的专用工具要简单,这在大多数组织中都是如此。 最后,我选择将其作为辅助项目进行构建,同时将大部分时间用于客户服务。 好处: […]
只需花几分钟的时间,就可以避免通过HTTP发送文件的麻烦,让我们看一下如何获取目录,并使用Swift在服务器上将其压缩。 我将向您展示如何以隔离的方式执行此操作,但是如果您有现有的Swift服务器应用程序,则可以轻松地将其添加到现有的代码库中。 因此,让我们从一个基本的swift应用开始,其中没有任何内容。 mkdir ziptest cd ziptest 快速包初始化 首先,在该新目录中,创建一个要压缩的新目录,并在其中放置一个随机文本文件: 接下来,让我们将库添加到Package.swift文件中。 添加到依赖项数组: .Package(网址:“ https://github.com/PerfectlySoft/Perfect-Zip.git”,majorVersion:2) 确定,因此将ziptests.swift重命名为main.swift(以便将其识别为可执行文件),然后打开并删除占位符内容。 我们在这里只需要几件事: 导入PerfectZip // zip对象 让zippy = Zip() //将文件压缩到源目录中, //放入目标文件,覆盖所有现有文件。 let zipResult = zippy.zipFiles(路径:[“ ../randomzip”],zipFilePath:“ ./randomzip.zip”,覆盖:true,密码:“”) // ZipResult包含带有操作结果的枚举。 打印(zipResult == .ZipSuccess,zipResult.description) 现在让我们执行我们的小应用程序: “ swift build” ,然后“ .build / debug / ziptests” 现在,解压缩几乎完全相同: //实例化zip对象 让unZippy = Zip() //将文件解压缩到目标目录,启用覆盖 让UnZipResult = unZippy.unzipFile(源:“ ./randomzip.zip”,目标:“ ./randomzip2”,覆盖:true) […]
字典作为一线开关/盒 从技术上讲,您可以使用字典将switch case块重写为一行。 首先,创建一个字典,其中每个对都将大小写条件作为键,并将其对应的返回值作为值。 最后,由于字典在运行时可能有也可能没有键,因此我们使用nil合并运算符来处理默认情况。 例如,看看我们如何转换开关盒并返回带有其IndexPath的单元格高度: 自然,这种类型的重写将取决于您先前的逻辑有多复杂。 另外,请记住,并非总是单衬板是最佳选择。 您应该始终优先考虑代码的可读性。 但是,拥有另一种选择总是很好。 可变参数 可变参数是函数参数,其行为类似于常量数组,但在调用时以不同的方式表示。 代替使用数组符号,传递的元素用逗号分隔。 如果要使用这些参数构建自己的函数,只需声明参数的类型,后跟3个点。 例如,查看以下简单的UIView扩展以在单个调用中添加多个子视图: 在这里,我们可以根据需要传递尽可能多的参数。 但是,每个函数只能有一个可变参数。
因此,上一次,您在Swift中创建了第一个程序(恭喜got),并且了解了什么是变量以及如何使用它。 今天,我将向您解释我们知道哪些变量,什么是常量以及我们如何使用它们。 首先让我们谈谈变量和常量之间的区别。 简而言之:变量可以更改或更好,可以更改而常量不可以。 当您要存储可以更改的消息(例如上次)时,可以使用变量,因此不需要很多不同的变量,只需为其分配一个新值即可。 你知道怎么做对吗? 无论如何,为了安全起见,让我们再次看一下。 var message =“某些消息。” 简单的东西吧? 右🙂 但是,当您要存储值并保护其不被更改时,您会怎么做。 假设您要存储一个日期,例如生日。 在这种情况下,您可以使用一个常数。 要声明一个常量,可以使用let (对于变量,请使用var )一词,它看起来像这样: let Birthday =“ 1990年8月1日” 现在,您创建了一个不可改变的常量。 如果尝试为它分配这样的值: 生日=“ 1989年5月23日” 它将返回错误消息:“无法分配值:“生日”是“ let”常量。 也许您在问自己,但是如果var“更好”,为什么我们需要这个,这取决于情况。 稍后您会看到有时保护一些数据不被写入会更好,这就是为什么要使用常量的原因。 好的,现在我们把这部分弄清楚了,让我们看看我们知道哪种类型 。 种类 串 您已经知道什么是字符串 ,您之前使用过吗? 所有用双引号引起来的值的变量都称为字符串 。 如您所知,字符串可用于保存文本数据。 字符串可以被修改,转换并可以保存许多类型的值。 例如,您可以使用+运算符连接多个字符串: 让名称=“杰克” 让姓=“迈克尔斯” 让生日=“ 1700年1月10日” 哇,这家伙老了😀 那么,如何才能将他们团结在一起? 像这样: 让combinedString =“你好,我的名字是” +名字+“” +姓氏+“,我出生于” +生日 这将打印出来(稍后我们将进行介绍): “你好,我叫杰克·迈克尔斯,我在1700年1月10日感到无聊。” […]