VIPER是首字母缩略词,代表可被视为干净架构的设计模式示例。 本质上,使用干净的体系结构,您可以将代码抽象为四层:实体(模型),用例(业务逻辑),控制器/网关/表示者(处理UI逻辑),设备/ UI / Web / DB /外部接口(框架)可能会改变)。 VIPER代表: V —查看(向用户显示信息并检测用户交互) I —交互器(通过获取数据和存储数据来操纵实体/模型) P —演示者(不使用UIKit,它包含与UI相关的业务逻辑并准备用于演示的数据) E —实体(您的模型对象) R —路由器(又称线框,负责模块/应用程序中的导航)。 VIPER体系结构可以使关注点更清晰地分离,并将viewController与处理应用程序中的大多数职责分离。 针对每个用例将关注点分为模块(即,为用户提供地图)。 每个模块都有清晰的路由逻辑,表示逻辑和业务逻辑层。 视图(视图控制器): 视图/视图控制器的主要目的是向用户显示信息并检测用户交互。 视图/视图控制器拦截用户事件,并且在VIPER设计模式内具有一个联系点: 演示者。 视图/视图控制器拥有并将用户操作发送给演示者。 例如, 视图/视图控制器将使演示者知道何时开始加载自身以及何时用户点击按钮。 主持人: 演示者从视图/视图控制器接收用户操作信息,并负责与UI相关的业务逻辑数据(但不包括UIKit!)。 演示者准备用于演示的数据。 演示者具有三个联系点: 视图/视图控制器 , 交互器和路由器 。 演示者负责从交互器中获取数据,并准备该数据以进行演示,然后将其传递回视图/视图控制器(以便可以对其进行更新),创建要移交给路由器的对象并确定是否要传递给路由器。需要来自交互器的更多数据。 我喜欢将主持人视为“调解人”。 交互器: 交互器了解我们的模型或实体 ,并从管理器类(即DataStore.swift)中获取并存储数据。 演示者要求交互器获取更新的数据,然后交互器将其提供回去。 交互器可以处理数据(即验证地图位置是否具有有效名称),并且可以调用帮助程序/管理器类(LocationStore.swift)创建实体 。 实体/实体: 实体是我们的数据模型(即MapName,MapCoordinate,MapLocation)。 这些实体由交互器操纵。 交互者完全了解实体及其属性。 路由器/线框: 路由器有一个联系点: 主持人 。 路由器 (又称线框 […]
展开序列(也称为“退出序列”)是一种序列,它允许用户从其当前视图控制器导航回先前的视图控制器。 想象一下:我有两个视图控制器和viewController1分别连接到viewController2。 用户在viewController2中创建或编辑数据,我想将此数据发送回viewController1。 放松的学习可以帮助解决这个问题。 为了说明我是如何使用放松搜索在两个viewController之间传递数据的,我制作了一个列出最喜欢的《狂人》角色的应用。 Segue:MadMenTableViewController-> AddCharacterViewController 第一个视图控制器MadMenTableViewController显示字符的tableView。 MadMenTableViewController导航栏中的“ +”按钮会将用户引导至AddCharacterViewController ,用户可以在其中将喜欢的字符的名称输入到textField中,然后在其导航栏中按下“保存”按钮。 展开Segue:AddCharacterViewController-> MadMenTableViewController 当我从AddCharacterViewController “展开” 序列以将新字符的名称(来自textField的字符串)返回给MadMenTableViewController时 ,我希望能够将此字符名称与展开序列一起传递,以便可以将其添加到数组中并显示在表格中。 故事板设置 在Storyboard中,从MadMenTableViewController中 ,我将导航“ +”(添加)按钮控制拖到AddCharacterViewController视图中,并选择“ Show”(例如Push)作为其segue类型。 AddCharacterViewController设置 在我的AddCharacterViewController中,我有一个称为character的存储属性,它将保存用户(从textField)输入的新字符的名称。 我重写了prepare(for segue 🙂方法,并从textField中解开了文本,并将其值分配给character属性。 正是在这个函数中,当取消缝合时,字符值将被传递回MadMenTableViewController 。 MadMenTableViewController设置 在我的MadMenTableViewController类中,我编写了一个@IBAction函数unwindFromAddVC(_ sender 🙂 ,该函数将在AddCharacterViewController取消 segue(单击“保存”按钮并退出AddCharacterViewController)时调用 。 上面,在#21行上,我有unwindFromAddVC函数。 该功能将接收字符名称字符串并将其添加到现有的“狂人”收藏夹数组中。 在#23行上,我检查看是否释放了segue的源是否是我想要的AddCharacterViewController 。 在第24行上,如果确实是我的AddCharacterViewController ,我将解包此senderVC并访问其character(String)属性(请记住,此字符串保留了我们角色的名称)。 在第25行上,此字符属性附加到我们的madMenCharacters数组。 在第27行,我确保刷新tableView,因为我们数组中现在需要显示一个新项。 将“保存”连接到“退出AddCharacterViewController” 回到Storyboard中 ,还有最后一件事要做。 控件将AddCharacterViewController中的“保存”按钮拖动到其退出图标 (最右边的橙色图标)。 放开时,应显示MadMenTableViewController中的@IBAction方法。 选择它,构建并运行您的应用程序。 现在,来自第二个视图控制器的数据将传递到第一个视图控制器! 很简单! 一探究竟: 我在这个项目的仓库可以在这里找到。 […]
上周我打了个电话,被问到:“从编码训练营毕业以来,您学到了什么?”我开始对此进行反思,并考虑将时间和学习重点放在优先位置的方式。 如果您正在考虑参加编码训练营,或者刚从编码训练营毕业,或者准备从编码训练营毕业,那么我希望本博客对您有所帮助。 我将讨论帮助我制定“后训练营”计划的关键事项,并弄清楚什么有效,哪些无效。 确定优先事项 在12月完成训练营后,我知道我必须开始找工作,但不知道如何确定几项工作的优先次序,并且有几个问题: 我应该建立自己的应用程式吗? 我自己的应用应该多久才能在App Store中出现? 我应该开始联网吗? 每周/每月我应该参加几次聚会? 我应该练习/复习哪些iOS技能? 我应该在白板练习/算法上花费多少时间? 我应该支付任何资源(Ray Wenderlich,Udemy,Udacity,GitHub,Big Nerd Ranch)吗? 我应该多久向前任老师寻求帮助? 如您所知,毕业后一周内我有很多思考。 实话实说,我花了一个月的时间来思考这些问题的答案。 以上所有问题的最重要答案是: 您需要更好地编写代码 。 归根结底,我的首要任务是要更好地开发iOS。 一旦确定了专注于改进代码的第一要务,我便为自己制定了一些迷你目标。 弄清楚(最重要的)什么是自己优先的。 继续使自己适应这一优先事项! 设定CCR(清晰,具有挑战性,合理)的目标 一旦了解了自己的优先级,便为自己设定了一些CCR目标。 我从作为Kunskapsskolan老师的那一天起就想到了“ CCR”的想法。 CCR代表“清晰,具有挑战性和合理性”,我每天都会用这些词来设定最终目标,中等目标和日常目标。 即使在今天,我仍在评估今天早上为自己设定的目标,即将我的最新应用程序推送到App Store(今天不会发生,但可能要到下周吗?)。 清楚了吗? 是的 有挑战性吗? 绝对,我至少还需要完成三个功能。 合理吗? 哎呀! 我无法在阵亡将士纪念日周末建立三个新功能。 因此,让我们讨论一下我的目标: 最终目标:获得iOS Developer的职位。 长期目标:在App Store中投放众多优质应用。 中目标:每周学习有关iOS开发的新知识。 每日目标:提交代码! 显然,从新兵训练营毕业后,我的目标是找到一份工作,但是我如何为自己做到这一点设置道路? 我为自己设定了一个目标,即每个月在App Store中放置一些内容。 它给了我30天的时间来提出一个想法,并将其贯彻到底。 我花了30天的时间来考虑我想学习和使用的框架。 它给了我30天的时间来使用UI,并弄清楚什么有效,哪些无效。 应该注意的是,这个每月应用目标与否定因素有关。 首先,我太专注于在App […]
今天,我正在进行一个副项目,该项目要求用户输入邮政编码才能找到本地餐馆。 我考虑过如何验证他们的邮政编码条目,以查看它们是否实际上是真实的美国邮政编码。 在进入代码之前,请注意一些有关邮政编码的有趣事实: ZIP代表“区域改善计划” 萨克斯第五大道的制鞋部门有自己的邮政编码:10022 由于邮件的增加,标准的5位数字长度是在1963年实施的。 这是我创建iOS应用程序的方法,该应用程序检查给定的5位数字是否为有效的美国邮政编码: 步骤1:获取有效的美国邮政编码数据(以CSV格式)。 我使用了从美国邮政编码下载的Excel电子表格数据。 我选择了“个人”帐户(即免费),因为我会将数据用于博客目的。 邮政编码数据库–邮政编码列表 下载Excel / CSV /电子表格格式的邮政编码列表,包括州,城市,县,区号,纬度… www.unitedstateszipcodes.org 注册免费/个人帐户后,我下载了一个zip_code_database.csv文件(如果需要,您也可以将其下载为.xls)。 步骤2:将CSV数据转换为JSON。 我使用网站Convert CSV将CSV转换为JSON。 CSV到JSON转换器 将CSV数据转换为JSON www.convertcsv.com 在网站上,要生成输出,我选择了“ CSV到JSON列数组”转换类型进行下载。 单击“下载结果”后,我收到了一个名为convertcsv.json的文件。 步骤3:重命名JSON并拖入XCODE项目。 我将文件重命名为zipcodes.json 。 步骤4:编写代码以读取JSON邮政编码。 我创建了一个名为ZipCodeStore.swift的文件来保存此逻辑。 1-我编写了一个静态函数,该函数将发送带有一个Ints数组的完成闭包(将是有效的邮政编码!) 2 —我在项目中解包json文件的URL位置,并通过资源名称和扩展名类型对其进行标识。 3-我将此文件转换为数据。 4 —我将此数据序列化为JSON对象。 5 —我将json转换为适当的类型[String:[Int]]。 6 —我访问json中的“ zip”键以获取我的邮政编码数组。 7 —我使用zipArray设置完成。 步骤5:构建UI。 在情节提要中,我拖了一个文本字段,一个按钮和一个标签。 我确保仅使用数字键盘输入了文本字段的文本。 然后,我建立了从Storyboard到ViewController.swift文件的插座和动作连接。 8 —这些是上述视图元素的出口。 步骤6:使用邮递区号资料建立本机阵列。 9 —创建一个Int的zipArray,它将保存从json返回的邮政编码。 10 —在.readJson函数上调用完成时,我将zipArray与返回的邮政编码数组(邮政编码)一起注入。 […]
在此博客中,我将讨论如何实现简单的集合视图。 这简单! 集合视图是有序的布局显示,与表格视图相比,可以进行更多的自定义。 如果要以类似网格的方式显示多个图像,我希望在表视图上使用集合视图。 如果我只想显示一个简单的列表,则可以使用表格视图。 对于此博客,我将从iTunes RSS feed生成器中检索数据。 该应用程序将在iTunes中显示美国排名前10的有声读物。 步骤1:添加收藏夹视图 在Main.storyboard中 ,将集合视图拖到视图控制器上。 添加约束以使其与父视图的边缘对齐。 添加约束以使其与父视图的边缘对齐。 步骤2:将View Controller分配为Collection View的数据源。 请注意,我没有将View Controller分配为Collection View的委托,因为我只是在显示Collection View单元,并且不希望用户具有可突出显示与所显示的单元进行交互的任何功能。 步骤3:在ViewController.swift中 ,遵循UICollectionViewDataSource协议。 步骤4:在我们的ViewController.swift文件中创建一个集合视图的实例。 步骤5:创建一个CollectionViewCell.swift文件。 此CollectionViewCell.swift文件将具有用于UIImageView(用于书本图像)和UILabel(用于我们的书本标签)的出口。 在此类中,我们还将具有处理显示单元格内容的功能。 步骤6:在Main.storyboard中 ,选择集合视图单元,并将其类设置为“ CollectionViewCell”,然后将其设置为redirectIdentifier。 选中集合视图单元格后,在“ 属性”检查器中 ,将重用标识符标记为“ collectionViewCell”。 步骤7:将UIImageView和UILabel拖到集合视图单元格上。 根据需要约束它们。 步骤8:将UIImageView和UILabel连接到CollectionViewCell.swift文件中的相应属性。 步骤9:为有声读物创建数据模型。 创建一个名为Audiobook.swift的新文件,并标识此数据模型的属性。 请注意,我在“ coverImage”属性中将图像URL作为字符串输入。 Audiobook初始化程序将为每个Audiobook对象解析一个字典 。 步骤10:编写APIClient实现。 步骤11 :(可选)创建DataStore管理器类(单例)以处理根据返回的API JSON数据创建Audiobook对象的过程。 如下所述,我导入UIKit(因为我将书图像作为UIImages存储在此文件中)。 您可以看到我有一个有声读物数组和一个UIImage数组来存储这些要在集合视图中显示的对象。 这不是我最喜欢的组织对象的方式,但现在可以了。 您还将注意到,我有两个功能: getBooks(completion 🙂和getBookImages(completion 🙂 。 […]
在此博客中,我将逐步创建一个音乐播放器应用程序,以播放我最喜欢的歌曲之一:Purple Rain☔️。 在此应用程序中,我们将使用AVFoundation,这是一个Apple框架,可让我们记录/播放/编辑照片,视频和音频。 步骤1:建立使用者介面 对于我的UI,在Storyboard中 ,我拖动了一个带有三个按钮的工具栏 。 在Attributes Inspector中 ,我使用PLAY按钮,PAUSE按钮将按钮更改为Systems Items ,并在最后一个按钮上键入“ Restart”。 我还确保在三个按钮之间分别拖动了弹性空格键按钮项 。 步骤2:为这些按钮创建IBAction。 按住Control键,将故事板中的3个按钮分别拖到ViewController文件中。 确保每个连接都是一个动作 ,而不是一个插座 。 步骤3:选择歌曲! 我已经从iTunes下载了《 Purple Rain》这首歌,因此将其从iTunes拖到“项目导航器”窗格中(位于Main.storyboard下方 )文件中。 如果需要,复制项目。 当它出现在“导航器”窗格中时,我将其重命名为简单的名称,例如PurpleRain。 文件类型为.m4a 。 请勿将其更改为mp3。 当我尝试将其更改为mp3时,发生了坏事。 步骤4和5:导入AVFoundation并创建一个AVAudioPlayer。 就像我之前提到的,AVFoundation是Apple的框架,允许您播放/编辑/创建视频/照片/音频。 从Apple文档中: AV Foundation框架提供了一个Objective-C界面,用于在iOS和macOS应用程序中管理和播放视听媒体。 我们在顶部导入此框架,并创建一个AVAudioPlayer类的实例,该类正是这样做的,它播放文件中的音频。 第6步:编写一个函数来设置我们的歌曲和会话。 从Apple文档中: 音频会话用于与系统交流您打算如何在应用程序中使用音频。 音频会话充当您的应用程序与操作系统之间的中介,进而充当基础音频硬件之间的中介。 我编写了一个函数prepareSongAndSession()来处理此功能: 步骤7–13:设置我们的AVAudioPlayer和AVAudioSession。 由于我是从iTunes手动将Purple Rain歌曲拖到项目中的,所以现在它已成为项目Bundle的一部分。 #7 —我将歌曲(来自捆绑包)插入我的AVAudioPlayer中 。 我用“!”来敲它,因为我确定这首歌存在于项目中。 此操作将引发错误,因此将执行do / try / catch块。 转到“ […]
本周,我被要求研究Collatz猜想,并编写一个函数,该函数确定达到给定输入达到1所需的步骤。Collatz猜想以20世纪初德国数学家Lothar Collatz命名。 猜想背后的主要思想是,对于任何给定的数字n (即12),如果给定的数字是偶数,则您将是该数字的一半。 如果是偶数,则继续将结果数减半。 如果不是(意味着,如果数字为奇数),则将奇数乘以3并加1。继续应用这两个运算( n * 2或3 n +1),直到n = 1。 为了显示: 如果是偶数,我将被2除。如果是奇数,我将被3乘以加1。我继续这样做直到得到数字1。 上面,我编号了到达1的步骤。它花费了9个步骤。 在下面,我将研究如何计算代码的步数(当然是Swift!)。 注意:有时我会像“ Colletz”那样拼写“ Collatz”,对不起! 当n = 12时,无需递归即可运行此功能花费了0.009045888秒。 当n = 12时,使用递归运行此函数在其上次迭代中花费了0.000402969秒。 请注意,在第一次调用中,它花费了0.008834584秒,这比我编写的没有递归的第一个函数要少。 我希望您喜欢使用DispatchTime,并将带有for循环的函数重构为具有递归的函数,从而对Collatz猜想有更多的了解。 请在下面享受一点Gosling / Culkin递归。 资源: DispatchTime –调度| Apple开发人员文档 创建相对于系统时钟的时间,该时间自引导以来开始计时。 developer.apple.com