Tag: 最佳实践

NS for iOS Devs —应用程序生命周期

在Swift Post上以更好的格式阅读此文章。 每个iOS开发人员都需要了解iOS应用程序的可能状态。 知道该应用何时终止或处于不活动状态,使我们知道在幕后能做什么,哪些可能行不通。 应用程序在某些情况下(例如处理切换,应用程序间通信等)需要额外的工作。 为什么我们需要知道? 首先,我们应该对应用程序的启动做出适当的响应。 某些第三方库需要在应用程序的不同状态下进行设置。 另外,我们应该准备该应用程序以使其在前台工作。 我们可能需要提供不同的用户体验。 例如,我们的应用程序在进入前台时都可能要求输入密码。 另一方面,我们的应用程序可以像Dropbox一样在后台运行时上传图像。 甚至我们可能想在应用终止后从用户离开的地方重新打开。 因此,每个功能在不同的应用程序状态下需要不同的实现。 因此,在提供不同且更好的用户体验的同时了解状态和转换可能至关重要。 我们需要知道些什么? 事不宜迟,以下是状态的简要说明: 未运行 :应用未由系统启动或终止。 后台 :应用程序在后台运行,仍然能够运行代码。 但是此状态的持续时间由OS确定,并且代码执行可以随时中断。 如果开发人员要求额外的时间来执行一些代码,则时间可能会更长。 在某些情况下,可以直接在后台模式下启动应用程序。 例如,如果在收到远程推送通知时开始下载某些内容,则该应用程序可以在后台模式下启动。 非活动状态 :通常是启动应用程序的活动状态和背景状态之间的过渡状态。 例如,如果我们在应用程序处于前台状态时收到电话,它将进入非活动状态。 活动 :当应用程序处于前台并且可以接收事件时,它处于活动状态。 已挂起 :当应用程序处于后台状态时,系统将其挂起,并且该应用程序无法执行任何代码。 没有任何有关暂停事件的通知。 系统会自动挂起该应用程序。 我们如何知道何时进行状态转换? UIApplication是代表我们的应用程序的对象。 它会设置所有内容并启动应用程序运行。 UIApplication对象通过UIApplicationDelegate通知我们。 当UIApplication对象控制系统与应用程序对象之间的通信并管理事件循环时,我们在UIApplicationDelegate对象中编写我们的自定义代码,以处理应用程序的启动以及状态之间的转换以及更多其他事情。 因此,让我们看一下UIApplicationDelegate中调用了哪些方法,以及何时需要在每个方法中添加代码。 application(_ application:willFinishLaunchingWithOptions:) 调用willFinishLaunchingWithOptions ,我们知道我们的应用程序的启动过程已启动,主故事板或nib文件已加载,但该应用程序仍处于非活动状态。 如果我们的应用是由于特定原因启动的,例如远程推送通知或主屏幕快捷方式,则此信息将在options 。 这里要了解的重要一点是,在这些情况下,系统可能会调用其他UIApplicationDelegate方法。 例如,如果调用该应用程序以打开URL,则系统将调用application(_:open:options:)方法。 options为我们提供了必要的信息,以便我们对这些事件做出正确的反应。 另一个很好的例子是Twitter feed。 我们可以看到,无论何时终止Twitter iOS应用并再次打开,它都会从我们离开的位置恢复。 它不会一直滚动到顶部。 如果我们要实现相同的状态恢复功能,则所需的步骤之一是在willFinishLaunchingWithOptions调用UIWindow的makeKeyAndVisible()方法,而不是在application(_ […]

OCP:开放/封闭原则

开放/封闭原则促进了协议的使用,使您能够在不更改现有代码的情况下适应应用程序的功能。 早先的“打开/关闭”原理由Bertrand Meyer在1988年定义: “软件实体(类,模块,功能等)应打开以进行扩展,但应关闭以进行修改。” 这样的实体可以允许在不更改其源代码的情况下更改其行为。 不幸的是,Bertrand Mayer建议使用继承来实现此目标: “类是封闭的,因为它可以被编译,存储在库中,作为基线并由客户端类使用。 但是它也是开放的,因为任何新类都可以将其用作父类,从而增加新功能。 定义后代类时,无需更改原始类或打扰其客户。” 如果子类依赖于其父类的实现细节,则继承会引入紧密耦合。 Robert C. Martin和其他人将开放/封闭原则重新定义为多态开放/封闭原则。 它使用协议而不是超类来允许不同的实现,您可以在不更改使用它们的代码的情况下轻松替换它们。 协议已关闭,无法进行修改,您可以提供新的实现方式来扩展软件的功能。 这种方法的主要好处是协议引入了额外的抽象级别,从而实现了松散耦合。 协议的实现彼此独立,不需要共享任何代码。 如果您认为协议的两个实现共享一些代码是有好处的,则可以在协议扩展中提供实现。 聪明的应用程序设计和代码编写部分应注意在应用程序的开发和维护阶段进行的频繁更改。 开放关闭原则指出,代码的设计和编写应以添加新功能的方式完成,而对现有代码的更改最少。 设计应以允许将新功能作为新类添加的方式进行,并尽可能使现有代码保持不变。 在许多方面,该原理都是面向对象设计的核心。 遵循这一原则的是可产生最大收益的面向对象技术,如可重用性和可维护性。 罗伯特·马丁(Robert Martin)引用的敏捷原则,模式和实践: 符合OCP的模块具有两个主要属性。 它们对扩展开放,这意味着可以扩展模块的行为。 随着应用程序需求的变化,我们可以使用满足这些变化的新行为来扩展模块。 换句话说,我们能够更改模块的功能。 它们已关闭以进行修改。 扩展模块的行为不会导致模块的源代码或二进制代码更改。 模块的二进制可执行版本(无论是在可链接库,DLL还是.EXE文件中)均保持不变。 TDD不仅与测试有关,更重要的是与设计有关。 有许多设计模式可以帮助我们扩展代码而不进行更改。 例如,装饰器模式可帮助我们遵循“打开关闭”原理。 同样,工厂方法,策略模式或观察者模式也可用于设计易于更改的应用程序,而只需对现有代码进行最少的更改即可。 在SRP中,您需要对分解以及代码中绘制封装边界的位置进行判断。 在OCP中,您将判断要在模块中进行哪些抽象,然后让模块的使用者进行具体设计,以及要自己提供什么具体功能。 关于这个原理,有一个有趣的类比,它指出“ 穿大衣时不需要开胸手术 。”这意味着,作为程序员,我们不应该冒险更改核心功能来添加简单功能并可能损害数据完整性。 本文在计算面积方面很好地说明了OCP的示例: https://academy.realm.io/posts/donn-felker-solid-part-2/ 让我们考虑另一个创建表单库的示例。 库为label,textField和textView提供了几个字段。 一段时间后,库开始出货,并且新的要求也开始为Switch UI提供支持。 如果在此枚举中添加新案例,并且客户端在switch语句中使用RowType ,则现有代码将中断,用户将不再使用库。 如果我们遵循开放/封闭原则,那么我们的系统将始终是可扩展的。 这些是Foundation和UIKit框架使用的“开放/封闭原则”的几个示例: URLSessionConfiguration default, ephemeral […]

NS for iOS Devs —查看生命周期

在 Swift Post 上以更好的格式阅读此文章 。 在学习了应用程序生命周期之后,视图生命周期在每个iOS开发人员的生命中都占有重要地位。 每个视图都是使用情节提要,XIB或编程方式创建的。 与方法无关,真正了解创建,加载,出现或销毁视图的时间有助于我们在开发屏幕设计,动画甚至业务逻辑时深刻理解我们的方法。 好的,但是为什么我们需要知道? 当我们考虑应用程序的生命周期时,我们很容易看到,随着应用程序进入后台,挂起等状态,某些事情正在发生。每当用户与应用程序进行交互时,就会发生某些特定的操作,并且应用程序的状态可能会发生变化。 但是,视图的状态可能会随着用户交互或应用程序数据的任何变化而改变。 另一方面,当视图中存在某种状态转换时,我们可能需要操纵用户界面。 例如,如果我们要使用自定义视图并将其设置为UIViewController的视图,则必须在loadView方法中进行操作。 或者,如果我们的设计要求我们在横向和纵向模式之间有微小的差异,那么我们需要知道何时可以在代码中进行此更改。 因此,了解所有生命周期方法不仅可以帮助我们编写代码,还可以使我们更具创造力并实现高级用户界面。 我们需要知道些什么? 为了在适当的位置使用视图,我们需要知道何时创建,加载,显示,更改,消失和终止视图。 UIViewController子类负责管理视图(又称UIView )。 视图控制器具有一个根视图,它是一个UIView实例。 这里重要的是它们如何一起工作。 UIViewController处理UIView背后的所有魔力,而UIView只是向用户显示屏幕和某些内容。 UIViewController告诉根UIView对象何时进入屏幕。 首先,视图控制器创建其根视图并加载它。 加载后,它告诉视图出现在屏幕上,并在必要时消失。 此外,一个视图控制器可能是另一个视图控制器的子代。 因此,视图控制器的生命周期不仅关心其根视图,而且还包括与其他视图控制器的关系,就像它是否移至父视图控制器一样。 最后,视图控制器的根视图(也称为UIView)具有自己的内容和生命周期。 根视图具有其子视图,例如按钮,标签,开关或其他UIView子类。 在大多数情况下,并不是每个开发人员都考虑子视图的生命周期。 但是有一种常见的情况是将视图控制器嵌入另一种情况。 在这种情况下,我们需要为两个视图控制器的视图模仿生命周期操作,并在必要时调用适当的方法。 我们如何获得有关生命周期事件的通知? UIViewController有很多方法可以在发生某些特定操作时通知我们。 例如,我们可以重写viewDidLoad方法以在加载视图后立即执行一些操作。 或使用loadView方法将UIViewController的根UIView替换为我们的自定义UIView类。 我们将研究视图和视图控制器的组合之间的关系,以了解当前状态。 与其过多地关注每种方法的作用,不如介绍每种方法的重要意义以及何时使用它们。 UIView — UIViewController关系 loadView :这是加载视图控制器的根视图的位置。 view , UIViewController view属性为nil 。 如果要创建自定义视图并将其设置为view属性,则需要重写此方法。 如果使用Interface Builder创建视图和初始化视图控制器,则不得重写此方法。 重写此方法后,我们必须初始化自定义视图并将其设置为UIViewController view属性,并且永远不要调用super.loadView因为它自己创建视图并分配给view 。 最后,我们不应该直接调用此方法。 […]

NS for iOS Devs —可测试性

在软件开发社区中,测试通常是一个大讨论。 我们听到很多人说“如果您不编写测试,您就是一个糟糕的开发人员”或“如果您不知道如何编写测试,那么您做错了所有事情”或“测试是好的,但它们耗时”。 但是,我更喜欢说 “如果您不编写测试,那就可以了。 只需尝试编写它们,您将最终了解其好处,并且您将学习和思考有关在编码之前所做的体系结构决策的更多信息。 我与很多人交谈,在聚会和会议上观看了很多关于各种测试的演讲。 一段时间后,我意识到相信通常的想法:“在iOS中,如果您有质量检查人员,则无需编写测试。” 这仍然不时地使我退缩。 但是,无论我们是否认为相同或不喜欢编写测试,我们都应该承认其好处。 相信我,当我看到及时带来的好处时,我改变了主意并开始编写自动化测试,即使我们有质量检查人员。 首先,我们应该考虑没有测试的工作流程,并确定(未来)问题。 让我们考虑一下只有一个质量检查人员而没有自动化测试的情况。 我们需要在编码之前和编码期间考虑所有情况。 仅仅因为人性,我们往往会犯错误。 这就是为什么手动测试有问题的原因。 会有不想要的行为。 我听说您,您有一个出色而勤奋的质量检查人员来测试构建。 但是小错误往往会被遗漏,并且可以通过自动测试轻松识别。 另一方面,当我们进行自动化测试时,我们倾向于减少错误。 我们创建测试用例并修复代码以使测试通过。 仅思考和编写这些案例会带来更多好处。 它们成为意图的记录。 它为项目中的新开发人员提供了足够的信息。 因此,在入职过程中,测试会拉平学习曲线。 编写更少的代码是大多数开发人员想要的事情之一。 通常,这是反对测试的有力论据。 但是,如果没有测试,我们最终将花费更多的时间来发现错误并进行修复。 没有一种简单的方法可以衡量其影响程度。 但是测试编写的项目往往更稳定,更可靠。 即使添加了新功能,我们也可以放心。 因为如果我们的更改影响了代码的其他部分,则测试失败将通知我们。 通过测试可以更好地做出体系结构决策。 我们将在以后的文章中讨论架构,但是我只想说,在编写测试时,我们最终会思考很多架构方法。 我们开始考虑单一责任和依赖倒置原则,以建立更好的架构。 有时我们需要对服务进行模拟或存根(通常在Swift中使用protocol来完成),这有助于理解面向协议的编程。 因此,我们在不知不觉中开始研究和学习更多的架构方法和设计模式。 最后,测试使代码审查变得容易。 如果我们已经进行了很多测试,我们将更有信心更改不会影响代码的其他部分。 而且,如果我们对拉(或合并)请求的内容不是很熟悉,那么通过测试,我们可以轻松理解该内容。 我喜欢Apple工程师在WWDC17的一次会议上说的话:“测试代码的代码审查,而不是带有测试代码的代码审查。” 好的,我们总结一下,直到这里。 手动测试存在错误,可能会导致不良行为 自动化测试功能强大,可为代码提供自我文档 自动化测试首先看起来很耗时,但从长远来看,它们可以节省更多时间 自动化测试可以帮助我们理解架构方法,甚至可以在不注意的情况下教很多东西。 自动化的测试使代码审查更加容易。 关于iOS应用编写测试的大量在线教程非常出色(下面是链接)。 在这里,我们将重点介绍要点和一些测试技巧。 “设计代码以实现可测试性” — John Sundell 正如约翰所说,我们应该问自己一个问题: “是什么使代码易于测试?” 。 […]

Xcode高级技巧第1/2部分

在本文中,我将介绍一个主题,它将帮助您提高工作效率。 对于程序员来说,使用快捷键非常普遍。以下是我的一些高级技巧的简要介绍。 1. Xcode欢迎屏幕:Sift + Command +1 欢迎屏幕对于切换最近打开的项目很有用。 2. Xcode设备屏幕:Sift + Command + 2 快速下载和浏览沙箱文档数据,例如plist,首选项,SQLite DB,缓存数据。 3.搜索时快速打开文件:Shift + Command + o 您可以使用“快速打开”搜索框来搜索和打开文件或符号。 符号可以包括变量,枚举,类型,常量,方法或类。 搜索使用模糊匹配。 例如,如果我要搜索“ application(_ application:didFinishLaunchingWithOptions launchOptions :)”。我只需输入“ appdidopt” 4.管理导航视图: 1.将文件添加到目标:Alt + Command + a 快捷键用于通过弹出窗口从实际位置添加文件以进行投影。 2.浏览以前的历史文件:Control + 2 3.浏览下一个历史文件:Control + 3 4.浏览通话记录:Shift + Control +命令+ H 最有用的XCode命令,可查看详细的调用堆栈历史记录,而无需导航到调用者文件。 要在导航视图中获取堆栈跟踪,请选择方法定义文本,然后在键盘中键入Shift + Control + command +H。 […]

ARC Swift中内存管理的第一种方法-第1部分

ARC代表自动引用计数,它是Objective-C和Swift的Clang编译器的功能,可以为我们管理内存。 每次创建类实例时,ARC都会分配一块内存,该空间将存储与该实例相关的所有信息。 一旦您的代码不使用它,ARC就会取消分配该类实例,因为应用程序不再需要它。 ARC仅适用于引用类型 ,不适用于值类型,如Swift中的“ 结构”或“ 枚举” 。 因为我想向您展示如何使用对象图管理内存,所以我在Xcode中创建了一个简单的视图项目,而不是Playground文件。 下面的示例显示ARC如何处理内存: 如上所示,为类实例分配的内存仍然存在。 即使将nil分配给’reference1’和’reference2’,分配的内存也不会释放。 这是因为还有另一个引用指向以前创建的实例,因此ARC在需要之前不会释放此内存。 您可以在下面的示例中看到: 尽管ARC通常可以成功地为应用程序管理内存,但是在某些情况下,我们需要提供额外的信息。 定义代码各部分之间的关​​系将有助于我们避免诸如强引用保留周期或内存泄漏之类的问题。 在前面的示例中,跟踪ARC如何为我们管理内存确实很容易,但是当我们开始编写复杂的代码时,这将变得更加困难。 因此,在向ARC提供信息时我们需要小心。 在编程时,我们最常犯的错误是有两个指向彼此的不同引用。 由于它们都是在内存中分配并使用的,因此ARC将永远不会释放内存,因为这种环境会导致强大的参考周期。 即使将“ nil”分配给这些实例,仍将分配内存。 在下一个示例中,我们将创建一个保留周期,并观察如何处理内存。 可以看到,没有调用’deinit’函数,这是因为类实例仍然存在。 提示:只需查看内存检查器中的紫色警告图标,即可轻松检测保留周期和内存泄漏 为了解决此问题,我们可以为参考提供额外的信息,以便ARC在管理内存时将其考虑在内。 在这种情况下,我们将把“ B”类到“ A”类的“ a”引用设置为“弱”以避免这种问题。 ARC是一项强大的功能,可帮助我们避免iOS上的内存处理。 但是,在某些情况下,我们需要特别注意。 将两个引用相互指向会导致强烈的引用周期,这不是预期的行为,因此我们需要通过提供一些额外的信息来避免此问题。 下一部分见,我们将通过一些示例了解这些关系之间的差异以及如何正确使用“ 弱 ”和“ 无主 ”。

Advanced iOS Developer(Swift)的最佳资源

以我的拙见,当然(更新10.12.2017) 很长一段时间以来,我的浏览器中都有一个文件夹,其中包含有关iOS开发和Swift的文章和视频,这对我阅读和重新阅读很有帮助。 我很确定大多数开发人员都有自己的具有最佳功能的库。 所以我决定分享我的信息Information 更新 12月10日:添加了调试部分 良好的iOS应用程序体系结构:MVVM与MVC与VIPER MVVM,MVC,VIPER…这么多缩写,哪种架构是最好的? 让我们来谈一谈永远重要的事情…… 学术领域 驯服极大的复杂性:MVVM,协调器和RxSwift 去年,我们的团队开始在生产应用程序中使用协调器和MVVM。 起初看起来很吓人,但是从那以后我们…… blog.uptech.team 汗楼| 协调员Redux 应用程序委托是任何应用程序的入口点。 它的主要职责是往返于……之间传递消息。 khanlou.com iOS架构模式 揭秘MVC,MVP,MVVM和VIPER medium.com MVVM简介·objc.io objc.io出版有关iOS和OS X开发的高级技术和实践的书籍 www.objc.io 汗楼| 8种模式可帮助您摧毁Massive View Controller 视图控制器之所以变得庞大,是因为它们做了太多的事情。 键盘管理,用户输入,数据… khanlou.com 依赖注入,iOS和您 脆弱的对象图之所以不好,是因为您无法轻松替换应用程序的各个部分。 如果是物体… www.bignerdranch.com 适用于Swift的SOLID原理– Marco Santa Dev 可维护的组件。 可重用。 只是个梦? 也许不吧。 SOLID原则可能就是这样。 SOLID是首字母缩写词… marcosantadev.com 依赖注入·objc.io objc.io出版有关iOS和OS X开发的高级技术和实践的书籍 www.objc.io 使用VIPER构建iOS应用程序·objc.io objc.io出版有关iOS和OS X开发的高级技术和实践的书籍 […]

Swift 4.1发布过程

这篇文章描述了Swift 4.1的目标,发布过程和预计时间表。 Swift 4.1是对Swift 4.0的源兼容更新。 它将包含对核心语言的一些附加增强功能,以及对Swift软件包管理器,Linux上的Swift的改进,以及对编译器和标准库的总体质量的改进。 Swift 4.1与4.0 不二进制兼容。 它包含各种幕后更改,这是在Swift 5中稳定Swift ABI的工作的一部分。 Swift 4.1计划于2018年上半年发布。 源兼容性 使用Swift 4.0编译器构建的绝大多数源(包括使用Swift 3兼容模式的源)都应使用Swift 4.1编译器进行编译。 在某些特殊情况下,这不能绝对保证。 这包括通过使用长期期待的泛型功能解决了使用泛型的问题,从而解决了编译器中的错误行为或极端情况。 但是,人们的期望是,大多数项目将在没有源代码更改的情况下继续构建。 -swift.org