堆是一个非常整洁的数据结构,可以对最小值或最大值进行优先级排序。 它与树的分层和节点结构有些相似,但是由于它是线性的,因此可以轻松地存储在数组中。 对于视觉人来说,如果我们将其绘制出来,这就是堆的外观: 上图显示了最小(最小)堆,该堆优先排列顶部数据集中的最小值作为根父节点。 在下面,存在值为3和8的节点,它们分别作为父节点的左和右子节点(值为2)存在。 值为3的节点的左子节点为4,右子节点为7。此过程将一直进行下去,直到所有数据集中的值都已布置好为止。 请注意,这些值通常随从顶部到底部的增加而增加。 它们本身不是从左到右组织的,而是按行组织的。 第1行在根节点的位置包含值2。 第2行的左,右子节点的值3和8都大于2。第3行包含了节点3和8的左右子节点。如您所见,两个节点的子节点在值。 希望您开始注意到一种模式。 最小堆中的每个父级可以有0、1或2个子级-所有这些子级的值都大于父级。 最大堆的工作方式完全相反。 堆利用索引系统(如数组)来确定值的顺序及其在堆中的位置(从索引0开始并向上计数)。 如果我们从较早之前引用可视堆图,则索引从上到下,从左到右递增,如下所示: 到目前为止,您所看到的示例都显示了静态数据。 我们没有添加或删除任何项目,但是最重要的是我们可以更改Heap中的数据,否则此数据结构将毫无价值。 在Swift中,我们将首先创建一个名为MinHeap的结构, MinHeap所示: 遵循堆的规则,您可以看到从上到下的每一行通常会逐渐变大,并且每个父节点的子节点都大于其自身。 调用peek()返回您期望的2值,而调用poll()在删除第一项后重新排列堆。 若要查看实际效果,请将以下代码添加到MinHeap结构的底部,然后再次调用dump(myHeap.items) : 我们做到了! 现在,我们已经成功地构建了一个最小堆,它对传入的最小值进行优先级排序。删除值后,堆将重新排序,因此下一个最小值位于顶部。 但是在现实世界中可以在哪里使用呢? 在Github Gist上获得完整的源代码:https://gist.github.com/kalub92/d269ba6b2bf05ca7dcbaae64b4ff7a2d 想象一下,您正在为儿科急诊室建立患者摄入系统。 医院希望优先考虑最年轻的患者,以便他们能够尽快接受护理。 想象一下,有几个6、7和8岁的孩子在候诊室,但一个病得很重的1岁孩子进入候诊室并经历了摄入过程。 在时间上,1岁应排在第4位,但该医院希望首先照顾最年轻的患者。 如果在患者摄入计划中使用了Heap,则1岁的孩子会马上去找儿科医生见面。 这是一个特定的用例,但我想知道您的想法。 您认为堆可以在现实世界中有用地实现在哪里。 在下面发表评论,让我们知道! 如果您准备加入我们并了解有关Swift,数据结构和iOS开发的更多信息,请查看Devslopes并注册我们的Apple坡度,以学习构建自己的应用程序和启动基于应用程序的初创公司所需的所有技能。 。
核心数据是一个框架,它隐藏诸如对象生命周期和对象图管理之类的持久层的逻辑,以帮助您以高级方式管理模型层对象。 是的,Core Data对许多开发人员来说都是有争议的。 但是,它仍然是有用的框架:性能良好,并且得到Apple的支持。 关于核心数据的单元测试,有很多不错的文章,但是大多数文章集中在模拟上下文。 由于发布了持久性容器类NSPersistentContainer,因此越来越难以模拟上下文并将测试写入容器。 因此,在本文中,我将探讨一个新主题:为NSPersistentContainer编写测试,增强型核心数据。 我们将一起使用NSPersistentContainer设置核心数据堆栈,并为此编写测试。 TL; DR 我们将学习如何: 使用NSPersistentContainer构建核心数据栈 使用内存永久存储 引入两个测试双打:“假”和“存根” 做一个异步测试 先决条件 迅捷3 Xcode 8 核心数据基础知识 iOS 10(由于我们将使用NSPersistentContainer,因此需要iOS 10)。 以下是一些有关核心数据的好文章: 完整的核心数据应用程序(代码在Objective-C中,但是概念相同) 核心数据入门教程 我们的任务 现在,我们有一个简单的任务:实现待办事项列表系统,在其中我们可以创建,读取,更新和删除待办事项(CRUD)。 而且这个待办事项系统应该永久保存数据,以便即使我们终止应用程序也可以稍后获取它们。 因此,我们需要实现这些方法: 创建待办事项 提取所有待办事项 删除待办事项 提交对永久存储的更改 由于我们只想在需要时执行保存,因此我们不会在创建/编辑/删除方法中将NSManagedObjectContext .save()视为副作用。 相反,我们将其设为独立方法。 当用户按下“保存”时将允许保存数据,或者当用户离开当前视图时将其保存。 尽管通过使用NSPersistentContainer在iOS 10之后设置Core Data堆栈更容易,但最好具有一些基本知识。 我们将在以下各节中采用这些概念。 因此,在下一节中,我将简要介绍Core Data堆栈。 核心数据栈 根据苹果公司的说法,核心数据栈是框架对象的集合,这些对象是核心数据初始化过程的一部分。 核心数据堆栈中包含4个基本组件: 托管对象上下文 (NSManagedObjectContext):为托管对象提供便签本 持久性商店协调器 (NSPersistentStoreCoordinator):汇总所有商店 托管对象模型 (NSManagedObjectModel):描述商店中的实体 持久对象存储 :包含已保存的记录。 […]
Model View Controller是我在iOS开发中学习的第一个概念。 您可以在iOS应用中看到最常用的设计模式。 苹果公司建议,它易于使用,并且相当容易理解。 如果您已经注意到有许多其他架构可以替代MVC。 在这里,我们将看到一个实用的列表,更重要的是这个问题的答案。 为什么MVC需要替代方案? 在MVC中,模型代表为该应用程序指定的数据模型。 视图是用户看到的应用程序的一部分。 控制器充当视图对象及其模型对象之间的中介。 它负责使模型相对于用户与View的交互保持更新,并负责通过Model的更改来更新View。 View会通知控制器任何用户交互。 然后,视图控制器更新模型以反映状态的变化。 按照定义,它们听起来是分开的,但实际上View和controller是紧密耦合的,而且每个人都知道另外两个。 这是所有问题开始的地方: 这违反了单一责任原则 这导致了一个普遍的问题,即所谓的Massive View Controller 这降低了每个实体的可重用性 代码的可测试性几乎是不可能的 在现实生活中,视图和模型是分开的,但是视图和控制器是紧密耦合的。 控制器和视图的所有代码都写在ViewController中。 View Controller可以快速将代码打包以用于各种目的。 这个问题称为Massive View Controller 。 Massive View Controller处于一种状态,许多逻辑和职责(例如网络连接,将Date转换为String和图像处理代码)已移入View Controllers。 这种做法会使您的代码庞大且难以更改。 它们显然不属于这里,但是我们应该将它们视为模型的一部分吗? 没有! 他们当然不是观点。 他们还能在哪里? 模型视图ViewModel在View和Model之间引入了另一个组件ViewModel。 该特殊层的主要目的是将数据状态从视图控制器移动到ViewModel(MVVM将视图和控制器都视为View ,并将视图控制器视为View)。 出于几个原因,MVVM成为了流行的iOS体系结构。 它着重于将用户界面与其他层分开。 MVVM与您现有的MVC架构兼容。 这种分离使应用程序更具可测试性,因为ViewModel对View一无所知。 通过使用MVVM,您可以将整个业务逻辑与曾经在MVC中耦合的UIKit分开。 视图模型 ViewModel是UIKit独立的视图及其状态的表示。 它从视图接收用户交互,从模型中获取数据,然后将数据处理为一组准备显示的属性。 这些属性中的每一个都代表视图中的UI组件。 有关为UI准备数据的所有逻辑(例如,将日期转换为字符串)发生在ViewModel中,而不是View中。 因此,可以为这些逻辑编写更简单的测试,而无需了解View的实现。 在MVVM中,没有直接在View中进行任何更改,我们在ViewModel中处理业务逻辑,因此View也会相应更改。 在观察ViewModel的更改后,View会自动更新。 […]
在继续学习Swift编码的过程中,我已经达到了第一个成功点。 完整且有效的游戏。 它是CandyCrush的副本,是在此非常有用的教程的帮助下制作的。 我花了几天的时间来完成课程。 我在这里和那里都遇到了一些主要与错别字或代码错误有关的问题,但是解决这些问题是值得的。 尽管我仍然无法从头开始创建自己的应用程序,但按照这样的指南进行操作,并继续阅读Apple的“使用Swift开发应用程序”,这是通往未来基础的道路。 CookieCrunch教程给我带来了一些挑战,我将尝试自己添加一些挑战,但是我不想花太多时间在此上,所以如果我不马上解决,我会参加另一个指导课程,以帮助我继续建立这个基础。 通过这些教程的工作确实使我大开眼界,了解创建我们每天使用和喜爱的应用程序涉及多少工作。 我羡慕那些希望并最终获得他们的大发布的独立开发人员。 我希望有一天能成为发行版的风口浪尖,但是即使那样,发行版也只是我们面临的第一个战役-获得可见性是一个“万无一失”的蠕虫。
在应用程序界面上倒入测试仪,在界面上进行测试时应遵循的原则,或者在最佳方式下可以使用此方法。 检验界面的刚度,强度和脆弱性 。 借用:解决方案选择的技巧,未经测试的临时执行子接口。 Ils nesont pas force与工业化完全兼容(例如:une executiondéclenchéeau commit)。 德,法执业者和劳力士。 僵化 : 更改设备的测试界面,维护时间不长。 脆弱 :经验丰富,执行力十足,而詹姆斯·加兰蒂则无能为力。 最好的解决方案,最好的方法是合理的使用。 识别和测试双重接口的界面(KeyFeature) 。 Ces parcourscléssont la raison d’êtrede votre应用程序。 倒入商业应用程序:测试或测试面板。 在界面上倒入测试器,并在其他可信任的地方使用BDD( 行为驱动开发 )。 一流的测试人员和界面的测试人员 ,快速和强大的测试人员,可以很好地融合各种测试方法 ,以方便地定位和应用这种界面。 联盟架构MVVM ,最简便的BDD接口测试仪。 Un BDD peut tester la dynamique UI: d’un change de de couleur ou d’image 禁忌的立场 d’un segue ou de l’apparition d’un弹出窗口 […]
给iOS开发人员一个 表格视图 ,他将编写10多个有关如何处理单元格操作的实现。 由于我们在Chili Labs中经常处理表格和集合,因此我想提出一个通用的解决方案,以解决项目中的单元动作。 我之前的文章中介绍的使用单元配置器的解决方案效果很好。 因此,将其作为基本模式可能是一个好主意。 首先,让我们添加TableDirector类,该类将存储单元配置器,并将成为UITableView的委托和数据源。 首先,我们需要向CellAction枚举中再添加一种情况,并返回其hashValue。 这里最具挑战性的事情是如何将自定义操作传递给CellActionProxy对象。 可以通过NotificationCenter发送通知来完成。 我们可以为CellAction枚举添加扩展,以方便地发送通知。 动作数据将存储在结构中,并通过userInfo参数发送。 最后,我们需要在TableDirector类中订阅并处理通知。 现在我们可以调用“跟随”动作并进行处理。 而已! 现在,我们有了一种机制,可以通用地处理任何单元操作。 进行少量修改,即可用于处理UICollectionViewCell操作。
假设我们有以下视图控制器 类ListController:UIViewController { 覆盖func viewDidLoad(){ super.viewDidLoad() view.backgroundColor = .white } } 了解viewDidLoad 我们知道第一次创建viewDidLoad会调用viewDidLoad 。 因此,在单元测试中,如果使用viewDidLoad进行触发,则会陷入陷阱 func testSetup(){ 让控制器= ListController() controller.viewDidLoad() } 为什么viewDidLoad被调用两次? 在测试中被调用一次 在您的viewDidLoad方法中,您将访问第一次创建的view ,因此它将再次触发viewDidLoad 正确的方法 最佳做法不是自己触发事件,而是做一些事情使事件发生。 在单元测试中,我们只是访问view以触发viewDidLoad func testSetup(){ 让控制器= ListController() 让_ = controller.view } 原始故事https://github.com/onmyway133/blog/issues/52
软件开发是一项复杂的工作,随着您的应用程序的发展而变得越来越复杂。 限制应用程序的复杂性将带来更好的整体质量。 在本文中,我论证了开发开放源代码软件的重要性,但是,针对高质量软件的开放源代码的相同原理也适用于封闭源代码库。 应用架构 在设计应用程序时,您的设计通常可以归结为至少具有“模型”和“视图”。 网站上的视图是HTTP路由,而在(iOS)应用程序上,这是一个更加直观的视觉概念。 除了这两个以外,您最终可能还会拥有更多类别。 我相信其中的控制器,配置,缓存和DataRepositories还有更多可能性。 当我指通过模块进行开发时,我想到的是面向依赖的体系结构。 您的模型是应用程序的核心基本概念。 用户具有标识符,名称和个人资料图片。 此信息对于所有其他组件的功能至关重要,这意味着所有其他应用程序组件都取决于模型。 您的观点是您将要使用的最高级概念。 这意味着视图(间接)依赖于所有其他模块。 由于视图依赖于这些模块,因此无法与类似模型的概念创建类似意大利面条的关系。 这迫使您的应用程序从下至上在结构上都是合理的。 访问修饰符 通过执行上述操作,可以减少应用程序数据对系统其他部分的偏见。 它有助于保持对数据结构的整洁有组织的监督。 但是,访问修饰符在这里比以往任何时候都更为重要。 忽略模块中模型的访问边界非常容易。 您为什么不将这些类型的“私人”更改为“公共”? 实际上,预防非常简单。 您的代码就像一堵砖墙。 砖块可能彼此并排,而不是直接相关。 一块砖将依赖于其他砖,而其他砖将依赖于该砖。 但是,从来没有两块砖头互相靠在一起。 这个基本概念对于创建稳定的软件至关重要。 编译时间 除了软件的结构质量外,您还将收获很多。 少了两个错误,更容易维护,这是我想到的两个问题,但是编译时间也肯定会增加,这并不是很明显。 软件通常是逐模块编译的。 这意味着在较小的模块中分离代码可以减少进行更改时需要重新编译的代码量。
斯威夫特(Swift)于四年前首次向公众介绍。 宣布这一消息之后,可以说是自最初的iPhone推出以来,在苹果主题演讲中最大的室内反应。 如果Craig Federighi的宣布使整个房间充满震惊和困惑,那么Chris Lattner令人印象深刻的演示就贯穿了其中,激起了人们的兴奋和惊奇,并急于下载Xcode以测试新语言。 一年半后,Swift开源了,预示着跨平台的广泛采用,Swift通常在Apple生态系统之外用于开发各种软件。 除非那没有发生。 Swift是开源的,但是更广泛的开发社区对此大加赞赏,自此以后,Swift在Apple平台之外并未取得良好的进展。 实际上,根据TIOBE指数,Swift的受欢迎程度正在下降。 退后一步,这不足为奇。 在非Apple平台上安装Swift有点令人头疼,除非您使用的是受支持的Ubuntu版本,否则您需要从源代码编译Swift,这是一个长达数小时的过程,并非出于胆怯。 Windows和Android有非官方的端口,但是由于它们是非官方的,因此不能保证它们会保持稳定,甚至将来不会编译。 因此,很明显,为了使Swift成长并在与苹果无关的和与苹果无关的各个不同领域中得到广泛使用,需要进行一些更改。 必须认识到,Swift并不适合所有人。 一些开发人员从根本上不同意Swift的发展方向-没关系。 重要的是,不要追随每个开发人员不同意Swift的目标,而要继续构建社区所相信的Swift,并让该语言立于自己的优点,以其核心原则吸引用户的注意。 换句话说,Swift无需更改其目标,原理或基本设计即可获得更广泛的使用。 为了使Swift成为通用语言,跨平台语言,应该怎么做? 毫无疑问,Swift由于与Apple密切相关而对某些产品的吸引力降低了,并且确实,Swift作为通用语言的成功取决于在开发人员的脑海中将Swift与Apple分离,至少有一点。 但是,请不要忘记,苹果公司是一家规模巨大且盈利的公司,迄今为止从未见过成功。 在将Swift与Apple分开时,重要的是要理解,认可和重视Swift不只是起源于Apple的事实,Swift 是 Apple。 您可能会问自己,“这是什么意思?” 好吧,让我列举一些苹果成功的公认原因: –硬件和软件是一起设计的,从而促进了其产品各个领域的合作和集成。 –周到,精美的设计。 –用户友好的界面。 –围墙花园方法。 现在,让我们看一下Swift设计的一些元素: –由一个团队开发,该团队包括Clang,LLVM和LLDB的创建者和主要贡献者。 近年来创建的许多语言都建立在这些基础之上。 迅捷团队的基础奠定了基础。 –现代,简洁,清晰,美观的语法。 –逐步披露复杂性。 –设计安全:没有指针,并且使用“可选”系统,在很大程度上不鼓励使用空值。 希望您领先于我,并且已经建立起一种联系,即我对Swift的描述仅仅是对苹果的描述,它被转换为另一个域。 Swift是Apple文化的产物,其核心具有相同的价值观和设计决策:Swift在其DNA中拥有Apple。 这是有价值的东西,而不是消费税。 因此,前进的道路必须是让Swift保持“敏捷”的一种方式-不惜一切代价保持其原理和文化,并且我们也不要太想把它与Apple分开,以免我们把孩子扔出去沐浴水。 尽管上述某些观点可以合理辩论,但我们重视Swift的人却看到并相信这些特征。 Swift将坚持自己的优点,而对它的原理有吸引力的开发人员将被它吸引。 您可能会想,“好吧,您已经谈论过Swift如何无法吸引非Apple生态系统开发人员,然后谈论了Swift如何出色并处于稳固的基础上,那么解决方案是什么?” 我想我有答案。 我认为很多人都有答案。 很明显。 Swift需要在更多平台上可用,它需要更易于安装,并且需要更好的工具支持。 除非有些公司想通过将开发人员分配给该项目在港口工作来直接投资Swift,否则要解决第一个问题并不容易。 从长远来看,我希望看到一个Swift基金会成立,并负责推动这类事情。 那是另一天的帖子。 更为紧迫的问题是,Swift目前在其支持的平台上并不容易使用。 是否想在受支持的Ubuntu版本上开发Swift应用程序? 希望您喜欢在文本编辑器中编码。 是的,确实有一些选择,例如安装了无数不同插件的Visual Studio […]
我一直在使用Apple Script作为Finder扩展程序FinderGo的工具。 由于沙箱,所有脚本都必须位于“ Application Scripts文件夹中。 今天,我正在重写我的Xcode扩展名XcodeWay。 在Xcode 8之前,我们可以使用Xcode插件和各种魔术使梦想成真在myway133 / XcodeWay:XcodeWay / Helper / FTGEnvironmentManager.m @ 1.0 #L50上。 但是自从引入Xcode Source Editor Extension以来,它不起作用。 所以我将XcodeWay重写为myway133 / XcodeWay @ 1.1.0 (发行版)的扩展 扩展程序必须在沙箱中运行。 如果将XcodeWayExtensions.entitlements App Sandbox切换为NO ,则不会加载。 因此,沙箱在很多方面限制了我想要做的事情。 在Xcode 9下,我无法使用NSWorkspace打开Finder 。 因此,我想我也可以使用Apple Script ,它的工作原理很吸引人。 唯一的限制是代码重用,因为我只知道如何运行整个脚本。 一种方法是导入其他Apple脚本stackoverflow.com/questions/2606136/import-applescript-methods-in-another-applescript,但我想我将在1个脚本中编写所有函数,并找出如何调用特定函数。 按功能,我也指处理程序,过程。 多亏了开源,我遇到了这段脚本编写器,这几乎启发了我。 所以这是我的脚本,其中包含许多功能。 这是ScriptRunner,解释了如何构建NSAppleEventDescriptor 。 请注意,您需要import Carbon 导入Carbonfunc eventDescriptior(functionName:String)-> NSAppleEventDescriptor { var psn = […]