Tag: iOS应用程序开发

在Swift中使用值类型进行双向关联

双向关联。 实体之间的双向关系。 例如,一个总统和一个国家,一个导演和他的电影等。这种关系是一对一,一对多还是多对多并不重要。 使用值类型无法完全表示它们。 由于值类型语义的原因,总会有不一致的地方 。 我将使用简单的示例尝试解释原因。 一对一 让我们考虑一下由总统管理国家的情况。 循环不断地进行……每次进行更改时,都会复制值,终止所有可能的值,以形成一致的关系图。 最后的话 由于不可变性,不可能仅使用结构来表示2向关系。 有时有必要依靠引用类型,即类。 我给你引用《 Swift编程手册》的一句话: …。这意味着大多数自定义数据构造应该是类,而不是结构…Swift编程手册

迅捷:链式铸造

正如我之前在Swift的类型推断中所提到的。 我真的对在我的代码中各处编写iflet和guard感到厌倦。 Swift中的类型推断 我要坦白。 我真的对在我的代码中各处编写iflet和guard感到厌倦。 有… blog.idapgroup.com 为了概述问题,让我们假设有一个UITableView ,其中我们需要呈现来自不同继承层次结构的UITableViewCell子类: 然后,让我们想象一下,Swift开发团队会使iflet失效。 众所周知,xCode Swift迁移工具并非始终可用,在某些情况下,我们必须手动重写代码。 我在Swift选择器上进行了这样的转换,这对我来说是一个巨大的痛苦。 而且,在我看来,iflets违反了我们所有人都喜欢和崇拜的DRY原则。 非DRY代码在重构或重写方面确实很痛苦,因为您没有集中的访问点。 为了解决这些问题,我更喜欢使用自己的解决方案: 稍后我们将详细介绍实现细节,但是现在让我解释一下,为什么我(不是真的)认为这种解决方案更好: 它使用类型推断; 富有表现力; 它是可扩展的; 它很健壮。 是的,我知道,对于任何不了解它的新手来说,它会使学习曲线更加陡峭。 是的,开关模式匹配也可以做到这一点,尽管语法会更加冗长。 但是它最终提供的是,只要我遵守界面,就可以注入任何我想要的行为,无论Swift如何改变。 当然,如果您愿意使用它,那将最终由您决定。 我绝对喜欢,因为我可以用更少的按键来表达相同的逻辑,并专注于真正重要的东西(我关于我要表达的内容的想法,而不是我要表达的想法)。 那么,它是如何在后台运行的呢? 请阅读我以前有关强制转换功能的文章之一。 为了更大的利益,我将在此处概述其签名,但是您需要知道如何使用它: 我提出的解决方案的实质是基于Castable泛型类型的: 首先,让我们回答一个最明显的问题:“为什么我们要在一种情况下使用switch ? 原因是很简单。 为了让Swift在没有默认返回值的情况下处理这样的表达式,该函数应该是穷举的,除了涵盖所有枚举情况的开关,Swift都认为该函数不是穷举的。 穷举是指处理所有枚举的情况。 此外, 如果case的语法更差: 这将失败,并在预期返回’NonExhaustive ‘的函数中缺少返回错误,并使用默认返回值作为self重写它可以解决问题: 但这只是为了自己的利益而编写的太多代码。 可能会出现的第二个问题是:“它是如何工作的?” 您看,我认为Castable作为一种类型可以通过两种方式进行处理:匹配和提取。 通过匹配,我的意思是强制转换一个包装的值,如果强制转换成功,则使用强制转换的结果调用该函数。 为了能够链接操作,我只返回了另一个包装相同值的Castable 。 提取只是解包并返回一个值。 从我的观点来看,通过一遍又一遍地重写相同的行来创建Castable不是一个好主意。 试想一下,每次要使用匹配和提取时,都必须编写Castable.value(x).match(…这是最常见的用例,对吗?可悲的是,我们不能只创建一个全局变量函数超出Castable.value初始值设定项,因为Swift不允许泛型使用该函数: let castableFunction = Castable.value导致错误:无法推断出泛型参数“ Wrapped”注意:显式指定泛型参数来解决此问题 。我能说什么Swiftc,你喝醉了,回家。 因此,为了修复该问题,我创建了几个最常用的功能-我认为是这样的情况: […]

iOS应用程序变薄(减小应用程序的大小)

图:显示了如何在XCode中启用位码 当使用第三方库和依赖项管理器(CocoaPods,Carthage)时,我们会遇到位码问题,因为某些第三方库可能不支持位码。 在这种情况下,请禁用位码,但是现在大多数流行的库都支持位码。 应用程式大小差异 以下是我们最新版应用之一的应用大小比较: 图:没有应用程序变薄 图:未启用位码但启用了切片 图:带有切片和位码 因此,应用程序精简可以将大小减少一半以上!(在大多数情况下) 了解下载大小对于那些刚刚超过无线限制的应用尤其重要,这非常重要。 要了解有关App Thinning的更多信息—您可以在这里找到Apple文档。

MVVM和协调器模式一起

今天让我们来谈谈创建应用程序时的常见问题。 应该选择哪种设计模式? 实际上,在构建iOS应用程序时可以使用许多模式:MVC,MVP,MVVM,VIPER等。这些是iOS中最常用的模式,每种模式彼此之间使用不同的方法,但最后哪种方法最好? 这取决于您从事的工作,项目的规模以及构建应用程序所花费的时间。 如果您想了解有关这些模式的更多信息,可以阅读本文:Bohdan Orlov的iOS体系结构模式。 现在让我们讨论两种不同的模式: MVVM :视图模型负责以易于管理和显示对象的方式公开(转换)来自模型的数据对象。 换句话说,这是模型和view / viewController之间的桥梁。 这是避免Massive视图控制器将逻辑移至View模型的一种绝佳方法。 协调者 :协调者或中介者将负责我们的应用程序路由(导航),然后view / viewControllers不需要知道它们在哪里或是否在导航内,它们只需要将导航操作发送到协调员/调解员。 MVVM运行中 首先让我们看一下MVVM的工作原理,以及为什么这对我们非常重要。 这有点容易理解它是如何工作的: view / viewController将事件或任务发送到viewModel viewModel执行任务(在后端中获取内容,执行操作,获取模型等) viewModel通过以下方式通知viewController:KVO,委托,回调,绑定等。 实际上,如今,如果您听到“ MVVM”,则认为是Reactive编程,反之亦然。 尽管可以通过简单的绑定来构建MVVM,但是RxSwift和RxCocoa将允许您获取大部分MVVM。 这样,我们将使用RxSwift来获取一些数据,并使用RxCocoa将数据绑定到视图来制作示例。 首先我们有viewController: 在这里,我们有好处: 分发 —现在,我们的viewController不再关心模型,它只是将事件发送到视图模型,并执行任务,完成后将响应发送回视图控制器,实际上视图控制器不知道什么真正发生在后台,因为现在这不是它的责任:)。 可测试性 – 视图模型对视图一无所知,这使我们可以轻松对其进行测试。 View也可能已经过测试,但是由于它是UIKit依赖的,因此您可能希望跳过它。 可重用性 -由于我们的viewControllers不执行特定任务,因此很容易重用项目中的大量代码和视图以及视图模型。 可扩展性 —现在,由于角色定义明确并且视图控制器并没有像以前使用MVC(大型视图控制器)那样执行很多任务,因此项目易于更改或更新。 是时候到协调员了 我们的应用程序看起来非常好,但是仍然有一个大问题,如果我要转到另一个屏幕,该任务由谁负责,viewController,viewModel,该怎么办? 答案不是全部,我们需要架构中的新元素来处理应用程序路由。 让我们尝试将协调器添加到我们的应用程序中,但首先我们需要了解应用程序应在何处以及如何运行。 好的,它看起来比以前非常相似,但是现在我们有了一个新的组件协调器,它负责处理应用程序路由。 通常,您的项目中有许多协调员,因为您的应用程序中有不同的导航和模块。 您可以将协调器与UITabBarController,UISplitViewController等容器相关联,或与UINavigationController之类的导航相关联,这些是应用程序中最常用的容器和导航。 每次您需要创建其中一个时,就知道需要一个协调器来处理流程:)。 现在是时候编写一些代码并观看协调员的实际行动了。 首先,让我们更改视图控制器以了解用户何时选择行。 这很简单,我们只调用方法modelSelected(Repository.self) ,然后将存储库绑定到视图模型。 现在更新视图模型。 在这里,我们有一些新东西让我们看看: […]

征服ReactiveSwift:SignalProducer(第4部分)

欢迎来到我的征服ReactiveSwift系列文章的第4部分。 在上一篇文章中,我们学习了如何创建和观察信号。 在本文中,我们将介绍SignalProducer的概念,它是Source类别下的重要原语。 定义 顾名思义, SignalProducer是产生Signal的东西。 基本上, SignalProducer封装了延迟且可重复的工作,这些工作在启动时会生成Signal 。 好吧,它有什么用? 请记住,在上一篇文章中,我们研究了以下问题陈述。 每隔五秒钟打印一次已过时间的消息。 我们创建了一个信号,该信号在接下来的50秒内每5秒发出一个整数。 然后,我们观察这些整数并打印经过的时间。 让我们假设,现在我们希望这从按钮轻按开始。 但是,作为观察者,我们只能观察信号,而不能使其开始或停止。 对于这种情况, SignalProducer非常适合。 因此,让我们开始吧! 我们将把整数发射代码封装在SignalProducer中。 //创建SignalProducer 让signalProducer:SignalProducer = SignalProducer {(观察者,生命周期)在 对于i in 0 .. <10 { DispatchQueue.main.asyncAfter(截止日期:.now()+ 5.0 * Double(i)){ viewer.send(值:i) 如果i == 9 {//标记第9次迭代完成 reader.sendCompleted() } } } } 在这里, SignalProducer用一个闭包初始化,该闭包在调用SignalProducer的 start方法时执行。 此闭包接受类型为Signal.Observer的观察者以及类型为Lifetime的生存期。 观察者用于发送值。 如果停止观察,则一生将为我们提供取消正在进行的工作的机会。 现在我们准备好了一个SignalProducer 。 让我们开始观察它。 //创建观察者 […]

iOS面试问题第5部分:核心数据📗

是时候挖掘核心数据了。 如果您错过了上一个第4部分:UIKit,请检查一下。 现在开始吧!!! 📀 问:持久性存储协调器可以有多个持久性存储吗? 持久性存储协调器将持久性对象存储和托管对象模型相关联 ,并向托管对象上下文提供外观,以使一组持久性存储显示为单个聚合存储。 它具有对托管对象模型的引用,该对象模型描述了商店中或其管理的商店中的实体。 在许多应用程序中,您只有一个商店,但是在复杂的应用程序中,可能有多个商店,每个商店可能包含不同的实体。 问:为什么我们需要多个持久性存储? 应用程序具有固定数据集,该数据集已包含在捆绑软件中 应用程序处理的某些数据是我们不希望保留在磁盘上的敏感信息 对不同实体有不同的存储要求 您可能已通过将文件包中的文件复制到可写位置并将其用作整个数据存储库的方式来满足第一个要求。 您可能已经通过手动删除对象来处理第二个问题。 在两种情况下,单独的持久性存储都是更好的解决方案。 每个持久性存储都有自己的特征-可以是只读的,可以二进制或SQLite或内存形式存储(在OS X上,也可以使用XML后备存储),也可以是您自己的NSIncrementalStore实现。 可以将模型的不同部分存储在不同的持久性存储中,以利用这种灵活性。 问:如何添加多个永久存储? 借助托管对象模型中的配置,我们可以实现这一目标。 我们可以创建多个配置并将其分配给不同的持久性存储。 我们希望每个商店一个配置 ,并且每个实体应仅添加到一个配置 (除了默认配置)。 实体可以具有多种配置,但是在这种情况下,您必须手动将每个对象分配给存储。 通过为每个商店创建一个配置并将每个实体分配给一个配置,我们使核心数据框架能够将实体定向到不同的商店,而无需任何进一步的交互。 问:我们可以在不同的持久存储实体之间建立关系吗? 您必须注意不要创建从一个持久性存储中的实例到另一个持久性存储中的实例的关系,因为Core Data不支持这种关系。 如果需要在不同商店中的实体之间创建关系,则通常使用获取的属性。 问:一个持久性存储协调器可以有多少个托管对象模型? 每个模型我们只能有一个持久性存储协调器。 问:持久性存储的类型? 问:持久存储安全性有哪些限制? Apple Docs说:Core Data 不保证不受信任来源(与内部生成的存储相对) 的持久存储的安全性,并且无法检测文件是否已被恶意修改 。 SQLite存储提供的安全性比XML和二进制存储好一些,但是不应将其固有地视为安全的 。 还应注意,元数据中存储的数据可能会独立于存储数据而被篡改。 为确保数据安全,请使用加密磁盘映像之类的技术 。 问:核心数据中的并发类型是什么? 两种并发模式NSMainQueueConcurrencyType和NSPrivateQueueConcurrencyType 。 NSMainQueueConcurrencyType特别用于您的应用程序界面,并且只能在应用程序的主队列上使用。 NSPrivateQueueConcurrencyType配置在初始化时创建自己的队列,并且只能在该队列上使用。 因为该队列是私有的,并且在NSManagedObjectContext实例的内部,所以只能通过performBlock:和performBlockAndWait:方法对其进行访问。 当您使用NSPersistentContainer ,viewContext属性配置为NSMainQueueConcurrencyType上下文,而与performBackgroundTask:和newBackgroundContext关联的上下文配置为NSPrivateQueueConcurrencyType 。 […]

大型iOS应用程序的最先进架构

介绍 我写了一篇有关将我们的iOS应用程序迁移到框架中以及该应用程序如何从此类工作中受益的文章。 本文将继续进行,并详细介绍迁移后在项目上完成的工作。 我描述了如何将内部开发的框架完美地链接在一起,以及应该遵循哪种模式才能为大型iOS应用程序实现真正的分离架构。 为我的PM记录……一切都在我的“产品空闲时间”中完成了🙂 动机 在我之前讨论的体系结构中,所有事物都属于一个适当的框架,主应用程序目标链接了所有框架,项目结构尽可能地分离,这提出了一个重要问题……将所有事物链接在一起的最佳方法是什么? 最先进的技术是使主应用程序目标(将所有框架链接在一起的应用程序)将责任委派给框架,然后通知框架需求,例如当前正在使用的框架想要呈现属于该框架的ViewController到另一个框架。 然后将通知主应用有关此更改,并显示所需的ViewController。 我希望您可以想象这种方法的所有优点。 首先,我想提一下可重用性,想象一下Facebook发生的情况。 他们的应用程序分为两部分(Facebook,Messenger),采用这种体系结构可以轻松实现这一目标,从而同时支持两个应用程序。 由于所有内容都在一个位置链接到应用程序,因此您也可以轻松地将整个框架/功能取出并链接到多个应用程序。 不用说,在团队中,每个开发人员都可以对某个特定的框架负责,但是在上一篇文章中有更多的责任。 三层架构 在上一篇文章中,我讨论了如何将应用模块化到框架中。 在本文中,我将把我们的项目分为遵循某些严格规则的3个逻辑层,以我们在该文章中所做的工作为基础。 第一层(胶水) 第一层包括我们的主要应用目标。 它具有AppDelegate对象,初始化我们的一些服务,响应通知等等。 除此之外,它还有我们的主要应用程序协调器。 协调员的职责是处理应用程序中的转换。 它从框架功能实例化协调器,并将责任作为其子协调器传递给他们。 儿童协调员将其不负责的行为通知父母(在我们的代码库中为主要应用程序协调员)。 我们之所以将责任从孩子协调员那里转移出去,有很多原因,主要是因为我们不希望一个孩子协调员依赖于另一个孩子协调员,如上图所示。 第二层(功能) 第二层具有我们的所有功能,例如发布项目,管理页面,聊天等。 这些框架中的每个框架都实现自己的协调器,该协调器将在第一层中实例化。 理想情况下,协调员应该是框架之外唯一公开可见的对象。 通过将框架协调器作为唯一可见的对象,我们确保这是与该功能进行交互的唯一方法。 第二层遵循严格的规则,不得链接第二层中的任何其他框架。 这样做的原因是要使功能与其他功能保持脱钩状态,因此可以很容易地将其带入或带出项目。 但是,第二层可以链接第三层的任何框架,并且被第一层链接。 话虽如此,第二层的框架可能需要具有一些共享的依赖关系,例如,功能框架很可能需要访问网络或持久性,这就是第三层的目的。 第三层(核心) 第三层是应用程序的核心,例如模型,网络,持久性,本地化等。第二层的框架由第二层链接,没有任何限制。 但是,与第二层不同,第三层的框架可以相互链接。 要避免在第三层建立这种联系将是极其困难的。 例如,您的网络框架(如持久性框架)将要使用模型框架……您可以想到许多类似的情况。 一种可能的解决方案是创建第四层。 只有第三层的共享框架才在第四层。 这可能是一个很好的解决方案,但是我们发现它有些过分设计。 这是一个工作区外观的示例。 实作 这是一个看起来很幼稚的例子。 在代码中,我使用术语流程代替协调器,因为根据我的观点,它是一个更准确的术语。 让我们从为Flow定义协议开始。 您可以在此处查看完整的演示。 流协议的实现 现在,让我们看一下主要的AppFlow(AppCoordinator)。 主AppFlow 最后,从其中一个框架实施子流程。 协调器模式已为人所知已有一段时间,有很多文档可以激发您的灵感。 我想在这里指出,我已经看到了一些实现,其中协调器接管了模型并正在获取数据或执行其他一些控制器/视图模型作业。 不用说,协调器是为应用程序流而设计的,这就是工作。 […]

类型擦除— Apagando tipos!?

向前,向后,向后,向前,向后,向后推荐方案的协议: https://www.raywenderlich.com/148448/introducing-protocol-oriented-programming https://developer.apple.com/videos/play/wwdc2015/408/ Mas por queiríamosquerer“ apagar” um tipo? 您可以在法律上迅速获得Swiftéuma linguagem fortemente tipada的权利 。 可以通过entãoiríamosquerer“ apagar” um tipo吗? 参赞者,vamos primeiro参评者,que queremos solucionar com essaestratégia。 Swift和jáse aventurou pelas suas的通用协议具有 maisavançadas,dave ter tentado usar与“ famosos” 相关类型 (tipos associados)。 注意 :在Swift 2.2中引入了相关类型,而在“ typealias”时代之前,它已被使用 Em resumo,um 关联类型 ,通用协议的“ nada maisédo que ”,“ propusade”的服务对象,parâmetro, “ retorno demétodos”等的服务。Imagine-o como uma caixa […]

该死,我们刚发售了一款游戏!

Marc Vandehey向您展示了如何在Swift 3中构建SpriteKit游戏 您是否曾经想制作一款游戏,却被开发和设计的复杂性所吓倒? 别害怕我的朋友,十三二十三有你的背! 这个由高级开发人员Marc Vandehey撰写的系列文章分为5部分,展示了为iOS平台制作SpriteKit游戏是多么简单。 小猫,小猫 游戏称为RainCat。 有一个简单的前提:我们要喂一只被雨淋困在外面的饥饿的猫。 具有讽刺意味的是,我们的RainCat不喜欢雨,潮湿时会变得悲伤。 为了避免猫科动物的悲伤,我们必须做个保护伞,尽力(作为保护伞)保持在RainCat上方,让她吃饭,并最终开心。 听起来很简单,对吧? 开发游戏也很容易! 下面列出了所有5个课程。 您只需开始: Mac电脑 Xcode 8 耐心,蚱hopper RainCat:第1课 如何在Swift 3 medium.com中制作简单的SpriteKit游戏 RainCat:第2课 如何在Swift 3 medium.com中制作简单的SpriteKit游戏 RainCat:第3课 如何在Swift 3 medium.com中制作简单的SpriteKit游戏 RainCat:第4课 如何在Swift 3 medium.com中制作简单的SpriteKit游戏 RainCat:第5课 如何在Swift 3 medium.com中制作简单的SpriteKit游戏 在 Facebook 和 Twitter上 找到我们, 或者在 thirteen23.com 上 与 我们 联系 。

在Elements第三部分锻造初级

凯拉 在我作为组织心理学硕士的一部分实习期间,我首先对编程感兴趣。 我在一家专门从事品牌研究的小型初创公司工作,除了进行研究外,我还被要求为新产品设计信息图形。 由于我没有设计经验,因此我在互联网上进行搜索,然后找到了所有可以学习的新技能的公开课程。 毕业后,我获得了荷兰电视新闻节目EenVandaag的研究员职位。 这也是我开始关注CS193p的时候,CS193p是斯坦福大学关于iOS开发的流行在线课程。 我之所以选择应用程序,是因为每个人都在使用它们,并且因为您可以使用GPS,运动传感器等,因此您可以对自己制作的应用程序类型真正发挥创意。 我之所以选择iOS,是因为我自己使用iPhone,因此可以立即在真实设备上看到结果。 课程结束后,我构建了一个小应用程序来展示自己的技能,并开始参加聚会以与其他开发人员联系。 这是我从Elements那里听到的,我非常感谢他们为我的Junior iOS程序提供了一个位置。 在这里,我不仅获得了关于编码的知识,还获得了有关Scrum和DevOps的许多宝贵经验。 当我回头看初级课程时,我对这么短的时间内学到的东西感到惊讶。 亚伦 我没那么久没写代码了。 在获得人力资源学士学位后,我开始在HR的房地产中介工作。 经过一年的“生存”,我感到自己和所做的工作之间没有爱。 那时我意识到我想要一些与众不同的东西,我可能会对此充满热情。 我回到教室,完成了信息研究的硕士学位。 在那儿,我接触了程序员和(移动)编程。 我不知道他们在做什么,但是我对如何以及为什么感兴趣。 成为硕士之后,我开始担任IT顾问,却忘了编程。 在我获得文学学士学位和IT硕士学位之后,这对我来说是合乎逻辑的一步。 可悲的是,我再也没有发现工作的乐趣。 我辞职了,知道自己想做什么:开始开发应用程序。 在硕士期间,我曾帮助设计应用程序,但我想学习如何构建它们。 我花了大约一个月的时间来决定iOS还是Android是适合我的平台。 最后,语言,IDE,产品和个人喜好使我朝着iOS开发的方向前进。 在Udacity获得两个iOS纳米学位后,我开始申请实习。 在一周之内,我收到了四家公司的报价,其中之一是Elements。 Elements是唯一一家为我提供专门的初级计划并且将我视为开发人员而不仅仅是实习生的公司。 我很高兴他们与没有任何专业技术经验的人取得了飞跃。 我们最近将我在Elements的合同续签了一年。 造成这种情况的主要原因很简单:编码标准很高,我觉得自己像家人一样。 初级项目和最佳实践 我们的第一个项目是为我们构建iOS Deploy +应用程序。 它涉及一个内部项目,该项目使该公司可以共享和下载移动应用程序构建的开发版本。 由于我们是应用程序开发的新手,因此我们感觉到了很多事情:使用Git,与JIRA一起,在Scrum团队中,与客户打交道(内部管理)和学习编码。 初级程序的优点在于,允许失败,并且有很多反馈可以解决! 实际上,我们开始注意到当我们开始工作第一个“真实”项目时学到了多少。 我们发现有一些关键的学习使之成为可能: 逐步学习,有时需要一些简单的步骤才能完全理解代码。 您会认为自己了解一些东西,但是下次您对同一件事进行研究时,您会更深入地认识到,在您不真正了解它之前(可能现在已经一样)。 不要沮丧:这是编码的一部分。 不要害怕问问题。 无论他们多么愚蠢,在您看来。 跟踪自己的进度。 如果某些事情延迟了您的进度,请尽快解决此问题。 不要只专注于编码。 应用程序开发的意义非凡,可以向不同类型的开发人员,设计师,质量检查人员开放学习。只需与您的同事交谈,因为他们可以分享自己的故事。 向他们学习。 最后,玩得开心! – […]