Tag: mvvm

MVP,MVC,MVVM和VIPER。 什么对iOS开发更好?

Same like every house has a solid basement, every software project, has an software architecture it is built on, and each project has its own app structure. The types of architectural patterns may vary, but there are 4 most commonly-used ones – the ones whole IT world continuously criticizes but keeps using at the same […]

使用MVVM清理架构

在本文中,我们将特别讨论使用DDD,TDD和MVVM的iOS应用程序的Clean体系结构。 通过分层实现关注点的高级分离。 干净的体系结构看起来是一个非常仔细的思想和有效的体系结构。 它极大地认识了用例和实体之间的不匹配,并将前者置于我们系统的主导地位。它还旨在最大程度地独立于任何可能妨碍应用程序可测试性或替换性的框架或工具。 。 实体:包含企业范围的业务规则。 用例:包含特定于应用程序的业务规则。 接口适配器:包含用于外围技术的适配器。 在这里,您可以期待MVC,网关的实现 框架和驱动程序:包含诸如数据库或框架之类的工具。 默认情况下,您在这一层中不需要编写太多代码,但重要的是要清楚说明这些工具在体系结构中的位置和优先级。 灵活 可测 容易明白 高维护性 可以与DDD等最佳做法很好地配合 尖叫-用例在项目的结构中清晰可见 复杂 学习曲线:比其他样式更难掌握 间接的-接口的数量可能超出人们的预期(我认为它不一定很糟糕,但是我看到人们指出了这一点) 没有惯用的框架用法-在这个领域,依赖规则是无情的 繁重的-从某种意义上讲,您最终可能会获得比当前项目中更多的类(同样,多余的类不一定很糟糕) 何时使用干净的体系结构:团队是否熟练和/或足够有信心,系统是否会比主要框架发布的版本有效? 系统是否会超过开发人员和利益相关者的就业机会? 交付模式,例如(MVVM,MVC,MVP) UIViews和UIViewController的位置 完全独立于平台 域的具体实现 隐藏所有实施细节 基本上,您的应用程序是什么以及它可以做什么(实体,UseCase等)。 它没有实体之外的实现 下载样例项目 ITHHKN /带有MVVM的清洁架构 使用MVVM清理架构–在本文中,我们将了解如何使用以下方法为iOS应用程序实现清理架构: github.com 参考: https://github.com/sergdort/CleanArchitectureRxSwift http://pguardiola.com/blog/clean-architecture-part-2/

iOS中的测试驱动开发,SWIFT 4-第2部分

该博客是我在iOS上的“测试驱动开发”的第一个博客的延续。 请对此进行深入了解。 如果仍然如此,您会为此感到懒惰,那么您可以下载此博客UT_Starter2的入门项目并继续。 让我们回想一下我们正在建立的用于DemoTestsProject的UML图。 因此,让我们写下测试用例。 在进行单元测试时,我们应牢记的重要一件事是,我们应始终尝试测试我们的公共方法和属性,而避免测试私有方法和属性。 等待。 什么!!! 你是认真的家伙吗? 原因是公共方法和属性是我们向外界公开的内容,并且不希望它们出错。 关于此有一个很棒的堆栈对话。 请随时查看。 为了显示位置列表,我们使用表格视图。 因此,参考我们的UML图,我们有一个PlaceTableCell 代表对应于单元格的UITableViewCell类。 PlaceTableCell 使用PlaceCellDataModel的数据模型 键入以链接其UI。 因此,我们将测试数据模型是否正确设置了属性。 导航到PlaceCellDataModel.swift 并准备您的测试课程,如下所示: 让我们首先写下模拟DataFetcher。 导航到PlaceListViewModelTests 并将以下代码粘贴到类声明之外,除非您希望一个类位于另一个类中。 😉 祝贺您的模块成功进行单元测试。 编写业务逻辑测试用例。 模拟数据。 模拟数据获取层。 遵循TDD概念并构建代码。 示例代码:您可以在DemoTests Repo的Final文件夹中找到完成的项目。 您可以通过以下渠道与我联系,以获取任何查询,反馈或只是想进行讨论: Twitter — @G_ABHISEK 领英 堆栈溢出 邮件 abhisekbunty94@gmail.com 为了立即连接 SkypeId — gabhisekbunty 请随时与您的其他开发人员分享。

如何将RxSwift与MVVM模式一起使用-第2部分

这是“如何在MVVM中使用RxSwift”系列的第二篇文章。 在第一部分中,我们从Cocoapods设置了RxSwift,并检查了如何使用Variable , Observable和PublishSubject 。 这次,我们将创建一个视图,可用于创建和更新服务器好友。 在激活提交按钮之前,我们还将看到如何验证所有文本字段中的输入。 之后,我们将检查如何在视图模型和视图之间的UITextField来回绑定数据。 如果您不熟悉“朋友”应用程序,则可以使用该应用程序下载朋友列表并将其显示在表格视图中。 您还可以添加,删除和更新朋友。 我已经使用MVVM架构实现了该应用程序,当然,我使用Vapor快速编写了后端! 如果您想在没有RxSwift的情况下学习基本的MVVM,请查看我使用Swift应用程序的旧MVVM模式。 您可以从GitHub获取该应用程序的源代码,记住要签出RxSwift分支。 当然,您也可以在没有源代码的情况下关注此帖子。 但是现在,让我们开始吧! 因此,我们的目标是向服务器添加朋友信息,并更新该信息。 我们将使用相同的视图进行操作。 我们有一个视图,您可以用来输入朋友的名字,姓氏和电话号码。 首先,我们定义一个名为FriendViewModel的协议。 然后,我们将有两个符合该协议的视图模型: AddFriendViewModel和UpdateFriendViewModel 。 在本教程中,我们将深入研究UpdateFriendViewModel 。 当我们打开编辑视图时,它执行与AddFriendViewModel相同的所有操作,并用朋友的信息填充文本字段。 与删除朋友的第一部分一样,还使用rx扩展中的功能设置了单元格点击。 现在,我们使用modelSelected函数并订阅其发出的事件。 首先,我们将检查单元格类型是否正常,并将viewModel与if case let语法绑定。 然后,将视图模型存储到新的ReadOnce对象并执行所需的ReadOnce 。 ReadOnce是一个帮助程序类,可确保在打开视图时不使用旧的视图模型: 该值存储在私有var value 。 您只能使用read功能来访问它。 如果您已阅读一次,则isRead设置为false。 下次调用此方法时,它将返回一个nil值。 当我们进入一个新视图时,我们总是创建一个新的ReadOnce对象,这使它更加安全。 现在,将旧值弄乱新视图创建的机会很小。 然后,我们可以检查是否应该执行segue。 在shouldPerformSegue内部,我们可以检查isRead变量。 如果返回false,我们可以继续。 现在我们知道执行了segue,我们将在prepareForSegue设置视图模型,如下所示: 这样,我们将确保始终使用正确的信息打开视图控制器。 这里一件有趣的事是updateFriends观察器。 更新朋友后,当我们返回朋友列表时,我们要确保列表是最新的。 这就是为什么我们必须设置观察者以在必须从服务器更新好友时获取事件的原因。 我们还想确保此观察者已从内存中释放。 如果我们对从内存中释放的视图控制器具有活动的可观察订阅,则可能会出现问题。 我们可以确定在控制台上打印“ ONCOMPLETED”时我们已经取消了订阅。 我们将在FriendViewController代码中回到这个问题。 然后,我将向您展示如何防止内存问题。 […]

我们喜欢软件架构模式

我们作为世界上的移动开发人员,通常会使用许多很酷的软件体系结构模式,通常都包含字母M和V(MVC,MVP,MVVM,VIPER),这会对新编写应用程序的人造成很大的挑战或困扰。 让人们重新关注这种模式应该做什么也很好。 有什么问题? 从头决定如何在大型应用程序中构建每个组件是多余的。 您面向用户的组件都将获取数据,然后根据该数据在屏幕上绘制并接收用户交互。 我们喜欢MVC / MVP和MVVM之类的设计模式或概念框架,因为它们提供了模型,视图和控制器之类的抽象对象来划分职责,并确保组件井井有条。 但是我想做更多的事情! 大多数时候,您将需要分离其他对象来处理获取数据,处理数据以及处理用户交互的后果。 最后,对这些背景对象的引用由与视图相关的组件保留。 当您需要分开职责,想要重用组件并帮助允许访问与视图无关的状态(例如,您有多少消息或是否已登录)时,可以这样做。 网络和数据持久性是经常需要分开的职责的示例。 处理这些组件的状态和状态,尤其是当它们可能在应用程序的多个页面之间共享时,变得很困难。 毒蛇巢 VIPER是一种比MVC更进一步的体系结构,它为更复杂的应用程序指定了各种额外的组件。 由显示内容并接收用户交互的视图 ,分析数据并确定要显示的内容的交互器和演示者 ,代表数据的实体以及路由器组成 ,以处理已显示的页面并进入新的页面。 这是一个很好的框架,请在此处阅读。 冲床 通常情况下,各个组件的状态会耦合在一起,这意味着您必须在不模拟整个应用程序或某些特定用户旅程的情况下,才能测试应用程序某一部分会发生的情况(“该错误仅在我尝试下达一个订单并取消它,然后尝试注销”-希望这永远不是真的)。 您还失去了对应用程序进行安全的结构更改的能力,因为您不知道后果将达到多远。 本质上,在应用程序的整个生命周期中,拥有一个良好的组件设计系统并实施通用样式,可以创建出更快地编写(希望),更易于维护(更易于理解和更改)并保持脱钩(也称为可测试)。 有关 首先编写测试会更好 苹果的MVC不是MVC 协调员,现在听起来很花哨

如何将RxSwift与MVVM模式一起使用-第1部分

本文全部涉及如何将RxSwift与MVVM结合使用。 几年来,RxSwift一直是swift社区中的热门话题,但是我设法避免了它。 我花了一段时间将自己的大脑切换到一切都是可观察的状态。 一开始我也遇到了麻烦,要弄清楚何时使用Variable , Observable , PublishSubject以及如何将值绑定到UI组件。 我将在此博客中介绍所有这些主题。 我将展示如何在MVVM中使用RxSwift,在RxSwift中使用UITableView ,如何编写网络层以及如何测试RxSwift应用程序。 我不会从头开始讲解MVVM模式,但是在阅读该系列文章之后,您将可以在MVVM中使用RxSwift。 如果您想学习MVVM模式的基础知识,建议您阅读我先前发布的带有Swift应用程序的MVVM。 我将通过展示如何编写一个名为Friends的应用程序来介绍这些主题。 您可以从GitHub获取该应用程序的完整源代码,只需签出RxSwift分支即可。 18个月前,我使用不带RxSwift的MVVM编写了该应用程序。 现在,我认为将其重构并查看将RxSwift与MVVM一起使用时的外观会很好。 朋友是一个iPhone应用程序,它下载朋友列表并将其显示在该应用程序中。 您还可以添加,删除和更新朋友。 因此,这是一个简单的应用程序,具有足够的复杂性,可以满足iOS应用程序的许多基本需求。 这也是开始学习如何将RxSwift与MVVM结合使用的好地方! 顺便说一句,后端是使用Vapor快速编写的! 在应用程序的第一部分,我将展示将RxSwift与MVVM结合使用的基础知识。 设置正确的CocoaPods。 在ViewModel和视图之间绑定数据。 使用UITableView ,显示一个加载指示器以及如何向用户显示错误。 我们将首先浏览实现的ViewModel端,然后是视图。 首先,我们需要将RxSwift添加到项目中。 在此示例中,我们将使用CocoaPods,但您也可以使用Carthage和Swift Package Manager。 查看GitHub仓库以获取更多信息。 在pod文件中,您需要添加: RxSwift添加了基本库,包括Observable , Variable , PublishSubject等。RxDataSources包括与UITableView和UICollectionView相关的反应式库。 RxSwiftExt帮助将可观察对象直接绑定到UI组件。 我们还将为我们拥有的测试目标添加所有库。 在完成Podfile的编辑之后,我们需要在终端中运行pod install 。 在如何将RxSwift与MVVM结合使用的第一部分中,我们将专注于应用程序的第一个视图: 第一个视图具有一个表视图,该表视图显示了从后端加载的所有项目。 为了展示所有这些,我们将FriendTableViewViewModel & FriendTableViewController 。 让我们从ViewModel开始。 ViewModel是使数据为视图准备就绪的模块(在本例中为FriendTableViewController)。 ViewModel还是我们放置大多数业务逻辑的地方。 我说“最”是因为我们应该避免在ViewModel变成另一个转储所有代码的地方的情况。 您可能听说过MassiveViewController问题,但我们也不想以MassiveViewModel结尾。 […]

iOS体系结构:MVVM

到目前为止,在软件开发中,MVC已成为最受欢迎的体系结构之一。 它已在每个网站,桌面或移动应用程序中使用。 但这是针对iOS应用程序的优化解决方案吗? 首先,让我们谈谈什么是iOS架构的良好设计? 在具有严格角色的实体之间均衡分配职责。 可测试性通常来自第一个功能(不用担心:使用适当的体系结构很容易实现)。 易于使用 ,维护成本低。 让我们再次谈论MVC定义。 MVC代表模型-视图-控制器。 模型:用于表示数据及其周围的一些逻辑。 视图:代表用户界面(UI)。 控制器:模型和视图之间的中介者。 它从View接收事件以修改Model并根据Model的更改更新View。 在这里,由于Controller是View和Model之间的中介,所以他们彼此之间并不了解。 这样好吗 在iOS中,模型可以是用于存储数据的NSObject类。 查看可能的UIControl,例如UIButton,UILabel,UITextField等。最后,Controller是UIViewController的子类。 等等,我说的是“查看”-控制器。 是的,不仅是控制器。 在Cocoa MVC中,Controller参与了View的生命周期。 UIViewController甚至是UIView的子类。 UIViewController处理用户在UI上的大部分交互,并且负责将数据从模型绑定到视图。 ViewController做很多事情:获取数据,显示UI,自定义动画等等。随着时间的推移,ViewController将成为大量的视图控制器。 您的代码将变得一团糟,很难阅读,调试和测试。 MVC仍然适合小型应用程序,但是,当您的项目越来越大时,实现单元测试是一项艰巨的任务,因为这些模块紧密耦合。 因此,我们需要尽可能地分离控制器,视图和模型,这是MVVM的需求。 MVVM:模型—视图— ViewModel 这里有什么新消息? ViewController与Model分开。 ViewModel现在是拥有模型的人,负责处理大多数应用程序逻辑,包括绑定数据,更新数据,获取数据等等。 从ViewController进行的所有数据访问都必须通过ViewModel。 现在,ViewController将处理用户的交互,显示数据并进行一些动画处理。 ViewController被视为View。 让我们通过一个简单的应用程序来详细了解。 用户界面只有1个表格,该表格将获取并显示一些漂亮女孩的照片。 这是我们的模型,它存储数据,并对这些数据有一些逻辑 ViewController有一个ViewModel将从服务器获取数据 ViewController将使用ViewModel来获取数据 从ViewController对Model的所有访问都必须通过ViewModel View(GirlCell)将使用一些参数通过函数将数据绑定到UI上显示 结果如下: 这只是一个演示,因此请忽略我难看的UI。 总结: IMHO,MVC或MVVM,甚至VIPER都有其优缺点。 决定要在应用程序中使用哪种架构取决于许多因素:目的,应用程序的大小,甚至是应用程序的潜力,……如果您要构建一百万个用户的应用程序,并且您的团队可能多达20人,那么应该是MVVM或VIPER。 但是,如果这只是展示您做某事的能力的一个小演示,请不要过多使用那些复杂的结构。 简单点,就是MVC。 结帐演示代码: https : //github.com/dzungnguyen1993/MVVM-Sample 在此演示中,我将Swift […]

创建MVVM GithubRepos项目iOS应用程序—第一部分(管理文件夹结构和Pod)

您是否曾经混淆过我们可以做什么样的项目来开始学习iOS中的MVVM设计模式? 在这里,我将尝试使用我自己使用Github API创建的示例项目来解释对MVVM的基本理解。 不仅使用旧方法MVVM,而且我还将给出RxSwift的一些基本说明。 首先,为了使其更易于理解,我将本教程分为几个单独的模块,每周更新一次或两次。 👌 就像初学者一样,当他们开始创建新项目时,首先想到的是什么? 结构! 是的,这有点棘手,但是从开发开始就管理文件夹结构非常重要,尤其是当我们在一个团队中工作并希望使我们的应用程序具有可伸缩性并且将来易于维护时,这一点非常重要。 CocoaPod呢? 什么是可可足? Cocoapod是iOS的依赖项管理器之一。 仅通过使用CocoaPods作为管理器,就可以使用尽可能多的库。 您无需执行困难的操作,例如将文件手动复制到项目中,也无需从原始存储库手动写入文件。 好吧,让我们一起开始做吧。 我假设您的终端中已经有pod命令,如果没有,请按照此处的步骤进行操作 如何安装可可豆荚? 我引用了太多链接并尝试过,但没有成功。 如果有任何想法,请与我分享。 我… stackoverflow.com

RxSwift视图模型的剖析

视图控制器中使用每个属性来驱动UI行为。 在此示例中,每个输入和输出都是一个Driver ,因此强烈建议使用Driver ,因为Driver始终在主线程上运行,永远不会完成,并且永远不会产生错误事件。 这使得视图控制器对那些Driver具有非常简单的响应。 将视图模型连接到视图控制器 看一下将这些Driver绑定到UI控件有多么简单: DisposeBag ,在新版本的RxSwift中,可以使用更好的样式将Disposable插入DisposeBag中。 现在,您可以使用相同的代码块执行以下操作: 视图模型初始化器 关于该视图模型的下一件要注意的事情是,使用格式正确的元组将输入和依赖项传递到初始化程序的简洁方法。 这种样式无疑使视图模型的输入是什么,并且还提供了对任何依赖项的清晰声明。 Zaher在评论中指出,在init方法的主体中, 一切都只是一个定义。 从输入序列到输出序列的纯转换。 该引言总结了MVVM视图模型最重要的一个方面: 将 输入序列转换为输出序列。 需要注意的另一件事:类上没有其他方法。 一切都在init函数中发生。 相反, SearchResultViewModel是确实具有实例方法的视图模型的示例。 让我们看一下这如何影响init的设计。 因为init方法在初始化所有属性之前无法访问self,并且因为他想在self上使用这些方法来准备imageURL和title输出,所以他被迫为它们提供一个临时值,然后用实际输出覆盖它们。 我不推荐这种方法。 在视图模型上避免实例方法 视图模型上的实例方法只会增加内存泄漏的风险。 这些方法的任何调用都需要引用self。 您必须非常小心, 不要 在闭包内部使用实例方法 。 Zaher不在任何闭包内使用它们,因此SearchResultViewModel没有泄漏。 但是我会争辩说,即使为此使用实例方法也为意外的内存泄漏打开了大门。 如在此重构版本中一样,最好使用文件专用顶级功能。 最终结果是GithubSignupViewModel2.init充当静态函数。 将其输出连接到控件后,不再需要返回的GithubSignupViewModel2实例。 输出将保留在内存中直到被处置,但视图模型实例本身已被释放。 这样可以确保没有内存泄漏。 视图模型可以是不变的结构 GithubSignupViewModel2可以很容易地成为一个struct 。 实际上,将其更改为一个struct ,它仍然可以编译并运行。 由于您只需要一个实例,并且由于其所有属性都是不可变的,因此对于此视图模型而言,实际上更喜欢使用struct 。 视图模型可以是一个功能 因为我们可以并且应该设计视图模型以在init方法内部完成所有输入到输出的转换,所以我们实际上只需要一个函数。 在下面的要点中,我将视图模型重构为顶级功能。 没课。 没有结构。 只是一个功能。 这是您可以粘贴在RxExample项目中的要点,以替换原始的GitHubSignupViewController2 ,然后编译并运行。 […]

iOS网络变得简单

最近,我学到了一种简单的iOS模式,该模式总是使我的头部受伤-网络。 我见过这么多具有​​不同目的和复杂性的解决方案。 但是直到最近,即使您是第一次看到,我也看不到任何通用,可测试和易于理解的东西。 当我加入我的上一个团队时,我们开始以反应性方式做事。 但是今天的教程将精简我们在团队中开发的版本。 本教程的目的是向您展示一种简单的方法来制作自己的内部网络库,这样您就不必依赖第三方库了。 1.打开一个名为“ NetworkLayer”的新Xcode项目。 假设您知道如何打开新的Xcode项目,那么我将把这一部分留给您解决。 2.接下来,我们将清理项目文件夹,如下所示。 我喜欢从一开始就保持项目整洁。 如您所见,我遵循经典的MVVM体系结构,其中大多数逻辑都存在于ViewModel中。 还有一个“网络”文件夹,用于存放与网络相关的任何内容,这将是本教程的核心。 3.那么我们要做什么? 在本教程中,我们将创建一个简单的GitHub客户端,该客户端将显示最受关注的仓库,并可以按语言进行过滤。 我们将基于公共GitHub API进行项目。 https://developer.github.com/v3/ 因此,我们将使用具有不同变体的https://api.github.com/search/repositories端点,以过滤要查看的存储库。 而且还将有详细信息屏幕,其中包含有关回购所有者的信息。 4,做骨架 相应地在文件夹中为UI和模型创建以下文件: 型号:Repos.swift,Repo.swift,User.swift,Response.swift 视图:RepoTableViewCell.swift ViewModel:RepoTableViewModel.swift,RepoTableViewCellModel.swift,UserViewModel.swift 控制器:RepoTableViewController.swift,UserViewController.swift 然后是网络层的核心: 网络:Networking.swift,EndpointType.swift,GitHubAPI.swift 最后,它应该类似于: 5.现在让我们用一些有意义的代码填充空文件 从更简单的内容开始,让我们用UITableViewControler UINavigationController替换Storyboard的内容。 将UITableViewControler’s超类更改为RepoTableViewController. 接下来,您应该自定义设计所需的单元格,但是在本教程中,我将进行通用介绍并显示Repos名称,描述,所有者的名称,语言和星级。 我的版本如下所示: 另外,由于我们要显示有关回购所有者的信息,因此我们需要另一个屏幕来显示用户详细信息,其中包含一些基本标签和图像视图。 6.接下来,我们将使用 Repos 和 Repo 模型。 在Swift 4中,有一个令人兴奋的新功能:带有Codable&Decoable 。 因此,我们将使用这种方式将json数据解析为模型对象。 希望您理解了这个想法,并且对您有所帮助。 我也在GitHub上发布了这个项目。 我必须感谢我以前的团队Sergei Guselnikov的合作伙伴,他是一位出色的iOS开发人员,因为这里包含的一些想法是基于我与他一起工作中学到的。 ✋️