Tag: mvvm

Swift中MVVM的面向协议的技巧

嗨伙计。 最近,MVVM已成为iOS应用程序的某种标准架构。 它提供了很好的关注点分离,格式化数据的好方法以及使用诸如RxSwift之类的框架的出色视图绑定机制。 在这篇文章中,我将提供一些技巧来简化该模式的实现。 可重用使视图变得简单 使用MVVM,视图与体系结构其余部分之间的分离非常清晰。 视图包括UIViewControllers及其出口。 实际上,实例化View变得越来越重要,特别是因为诸如Coordinator之类的模式越来越受欢迎。 在本文的其余部分中,我们将假定您正在实现这种体系结构。 Reusable是一种API,它带有对UIViews和UIViewControllers的便捷扩展,可以方便地以类型安全的方式实例化它们。 这是GitHub存储库:可重用。 它是与Carthage,CocoaPods和SPM兼容的轻量级API。 不使用它带来的幸福🖖真可惜。 基本上,Reusable提供了mixins(具有默认实现的协议),一旦您使它们符合适当的协议,它们就会向UIViews和UIViewControllers添加实例化函数。 在使用Coordinator模式时,有时需要实例化UIViewControllers并将其传递给ViewModels。 幸运的是,因为可重用在此方面有很大帮助。 这是将Reusable用于UIViewControllers实例化所需要做的事情: 为每个UIViewController创建一个Storyboard文件(当然,如果在同一个Storyboard中可能有多个UIViewController,但是为了简单起见,我们将仅考虑一个UIViewController) 将UIViewController设置为场景中的初始ViewController 创建一个UIViewController文件,其中ViewController类名与Storyboard文件名相同。 例如,如果故事板文件名为“ SettingsViewController.storyboard”,则UIViewController类将命名为“ SettingsViewController” 使UIViewController实现“ StoryboardBased”协议 就是这样。 现在,您可以使用单行代码实例化ViewController: 最酷的是, settingsViewController的类型是SettingsViewController ,不需要强制转换语句。 实际上,基于Storyboard的协议非常简单。 让我们深入了解一下: 基本上,它的作用是为实现该协议的每个UIViewController提供静态的“实例化”功能。 此函数返回UIViewController的实例。 由于“ Self”是函数的返回类型,因此类型推断可确保我们不必强制转换结果。 我强烈建议您深入研究可重用。 从类型安全的方式从Xib实例化UIView或使UITableViewCells出队时,这也将很有帮助。 面向协议的ViewModel 在当今的应用程序中,类似协调器的体系结构很常见,尤其是当与MVVM模式组合时。 这就是为什么我希望首先谈论Reusable的原因。 但是我发现有一个技巧非常有用,并且是可重用的补充。 它非常适合面向协议的方法中的MVVM模式。 这个想法不仅是为了简化UIViewControllers的实例化,而且是提供一种很好的方式来传递它们相关的ViewModels。 让我们写一个协议来定义拥有ViewModel的含义。 现在,我们可以将其与StoryboardBased混合使用,并提供一个静态函数,该函数以ViewModel作为参数实例化UIViewController。 条件扩展是一个非常强大的工具。 结合了“ StoryboardBased”和“ UIViewController”的“ where”语句使Self.instantiate函数可用,因此我们只需要将此调用包装在另一个设置UIViewController.viewModel属性的静态函数中即可。 假设我们有一个符合ViewModelBased协议的MyViewController: 使用ViewModel进行实例化将非常容易: 让我们进一步了解ViewModel抽象 到目前为止,我们仍然必须实例化ViewModel并将其提供给View。 […]

具有60个单元测试的示例iOS应用

无需功能性反应式编程的MVVM架构模式 在互联网上,缺少使用单元测试的应用程序的实际示例。 有一些关于抽象理论中的单元测试原理的文章,但是很少有明确的具体示例。 因此,我决定制作一个应用程序,以分享到目前为止我学到的一些知识。 这是运行该应用程序的视频: 代码覆盖率尚未完成,但没有必要达到100%: Xcode单元测试会在每个单元测试之前自动运行setUp()方法,并在每个测试方法之后自动运行tearDown()方法。 这些方法通常用于清除内存中状态,以防止其从一个测试传播到另一个测试。 在setUp()中,我调用resetState方法来清除数据事件状态。 在ShowsRepository中,我仅在内存中使用Realm来在每次运行测试时都不会在磁盘上保持状态,这可以防止单元测试相互干扰。 让配置= Realm.Configuration(inMemoryIdentifier:“ InMemoryRealm”) 假物件 进行单元测试必不可少的是假对象。 您可以在此处阅读更多有关为什么虚假物品如此重要的信息(“一种科学实验”)。 在应用程序中,我使用了虚假的应用程序委托。 委派的虚假应用只是对不执行任何操作的真实应用代表的空替代。 当启动应用程序时,检测目标是否与单元测试的目标匹配,如果是,我将实际的应用程序代表替换为伪造的应用程序代表。 因此,每次运行测试时,该应用程序都不会启动实际的View Controllers / Views。 这种方法允许以更隔离的方式运行单元。 这样对单元测试的运行时性能有好处,并且不会导致意外的后果。 单元测试中使用存根和模拟。 查看项目代码,您可以找到一个带有存根的文件夹,另一个带有存根的文件夹。 依赖注入 在单元测试中,可以用实物代替存根和模拟物,以具有更可控的环境。 当您在ViewController中执行tableView.delegate = self时,您将使用依赖项注入,因为委托是MapKit实现中的依赖项,因此您正在注入它。 是的,即使您还没有注意到,您多年来一直在整个UIKit进行依赖项注入。 代理和数据源隐藏在协议后面。 对于存根,程序员可以使用接口/协议以及带有覆盖的依赖项或子类的注入。 当然,接口选项比子类更好,因为它导致较少的耦合。 假设您有一个从A类继承的B类,而您的目标是测试B类。可以创建一个从B类继承的C存根。这里的主要问题之一是B类已经带来了很多A类行为,很难摆脱它们(或者它的僵化或不可预测性)。 您想要做的只是保持相似或可代表但可控制且可预测的行为。 为了进行依赖注入,我使用了一个名为Swinjec t (https://github.com/Swinject/Swinject)的第三方库。 没有第三方库也可以建立依赖关系。 但是,Swinject将依赖项存储在Container中,因此更容易将依赖项维护在中央位置,从而提高了代码的整洁度和凝聚力。 要获得实例,您可以执行以下操作: 让person = container.resolve(Person.self)! 这样,您无需在实例化时传递参数。 注册依赖项时传递参数。 使用Swinject,甚至可以将类转换为Singleton,而无需触摸该类的文件(开放式封闭原理)。 Swininject resolve方法尝试获取与特定协议关联的实例。 在单元测试中,我们使存根实现特定的协议(在实际应用中由实对象实现),并通过使用register方法将存根与协议相关联。 注入依赖关系允许更大的责任分离,有助于遵守Liskov原则,Open Close原则和依赖关系反转原则。 […]

UICollectionView:如何轻松处理更新

使用CollectionViews或TableViews时,困难的部分是需要添加,删除,移动某些单元格或更新其内容时。 使用装饰视图时甚至更多。 介绍 查看以下两个数组: let old = [“ A”,“ B”] let new = [“ B”,“ C”] 这些数组之间的差异非常容易计算: Deleted:[0] //旧数组中的索引 已移动:[(从:1,至:0)] 插入的:[1] //在新数组中的索引 重新加载:[] 要计算此差异,我们使用一个键比较两个数组,在这种情况下,这是数组中的值。 使用key,我们可以计算move , delete和inserts 。 删除了位置0的键A 钥匙B从位置1移到位置0 键C插入位置1 当我们要计算两个数组之间的重载索引时,它变得更加复杂。 我们还需要一个key和一个值。 如果值更改,我们需要重新加载该项目。 let old = [(键:“ A”,值:0),(键:“ B”,值:0)] let new = [(键:“ C”,值:0),(键:“ B”,值:1)] 差异的结果: 已删除:[0] //键A已删除 感动:[] 插入:[0] //插入键C 重新加载:[1] // B的值已更改 […]

带流量控制器的MVVM —第一步

我正在观看有关MVVM概念的KrzysztofZabłocki的视频,并认为只有一种方法可以理解某些内容:创建我的项目! 在深入了解应用程序体系结构之后,最近6个月我一直在研究带有MVVM协议的模型。 要了解其起源,必须引用Natasha The Robot的文章以及有关面向编程协议的所有知识。 如果您不知道我在说什么,那么好的主意是阅读Natasha The Robot 。 一个月前,我最终观看了Steve“ Scotty” Scott的MVVM-C讲座。 在我今年看过的最好的视频之一中,重要的防御不是缩写技术,而是架构可以帮助我们改进软件的。 对于捍卫技术“银弹”的人们,我没有什么反对的态度,但是我更喜欢这样一种策略:从每个创意中汲取最大的价值,以找到最佳的解决方案。 Flow的初始化程序将构建ViewModel和Model(如果需要,还可以创建更多模型)和start方法,并创建必要的接口并注入其依赖项。 这将使这些实体之间的耦合更多地利用代码。 我们可以看到在OwlsFlowController的情况下,通过配置选择是将数据显示为Grid还是List,在这种情况下,它是固定的,但它可能是测试简单的A / B。 此模型的优点是,大多数列表中的应用程序共享相同的行为和相同的接口基础结构。 在这种情况下,只有数据和单元格会更改,并且可以作为参数传递并为所有列表创建重用代码库。 这里一个有趣的想法是实现了两种响应协议:一种用于Grid,一种用于List。 但是两者的实现是相同的。 这很有趣,因为我对每种类型的接口都有单独的操作,但是可以共享常用操作。 并且不使用继承。 界面的实现清晰明了,它是一种客观的基础结构,具有简单的参数即可显示。 所有创建都被删除,使他没有任何业务实现。 另一件事是通过Closure填充了单元格,这将使我们能够在不久的将来传递使用哪个手机作为参数。 这种体系结构的思想是将接口分为两部分,第一部分是一系列现成的基础架构,可在整个项目中重用。 第二部分是针对每种情况和每种数据集定制的UIView和单元格。 因此,我们的大部分界面都已包含在通用测试中,从而提高了安全性。 PS:由于某些原因,在某些情况下,Swift不会接受Generic类型作为init方法的协议参数。 仍在调查Swift Bug或故意限制。 结果是非常干净的代码,并最大程度地重用了接口。 并探讨了泛型和协议作为抽象问题的一种方法。 其他结果是构建时间明显快得多。 这些是几周后的初步结果,我希望获得其他结果,并将在其他文章中进行探讨。 如果他们想继续关注Github,请尝试在“ Middle”(此处)或“ Medium”(此处)的此处进行很好的记录,我将把这些文章。 接下来的步骤,谢谢。 下一步 测试:带有模拟对象的单元测试和UITest(MVVM和测试) 展开模型:其他对象(我需要找到其他动物) 接口的基础结构:创建其他单元格类型并使用相同的UIViewController 我的下一篇文章将介绍如何构建有效且易于维护的测试。 为我交叉手指。 特别感谢 引用时,我试图标记所有阅读的内容,以写出这段代码,对不起,如果我忘记了别人。 我不能忘记感谢Mikail Freitas帮助我识别了通用协议的初始化错误。 我们永远不会理解为什么在一种情况下有效而另一种无效。 PS:Claire Knight(Twiter),她将项目迁移到Swift […]

iOS开发:The Woost Way™

在Woost,我们的承诺是在一个月内生产出最低可行的产品。 我们相信(几乎)每个新概念的核心都可以在该时间范围内构建。 我们帮助我们的客户找到核心,定义目标和假设,并缩小范围,直到一个月之内即可完成开发。 我们为网络(响应式)和移动(本地Android,本地iOS)构建。 为了能够加快速度并快速交付,我们拥有用于大多数项目的标准工具集和标准项目设置。 在本文中,我将向您介绍我们用于iOS项目的内容。 当然,随着每天都会出现新的最佳实践和新框架,这可能会发生变化。 警告:技术性越来越强😉 可可豆 其他人已经做了很多工作。 如果您知道如何珍惜他人*的工作,则可以节省大量时间,并避免通过使用轮子来重新发明轮子。 *: 这个很重要! 您应用的性能和稳定性至关重要。 CocoaPods是Swift和Obj-C项目的程序包/依赖性管理器。 您可以将CocoaPods集成到项目中,以轻松添加,删除或更新外部软件包。 我们主要使用CocoaPods,有时使用Carthage,但发现前者更易于使用。 我们或多或少的标准Podfile看起来像这样,已经使您了解了我们使用的工具: 吊舱“ RxSwift” 豆荚“ RxCocoa” pod’SwiftyJSON’ 吊舱“翠鸟” pod’PureLayout’ 吊舱“ R.swift” 豆荚“面料” pod’Crashlytics’ pod’Firebase / Analytics’#或’GoogleAnalytics’ 在设置Pod时,请确保还检查gitignore.io来创建一个漂亮的.gitignore模板! 我们通常从这一点开始。 接收 RxSwift是ReactiveX for Swift的一个版本(RxCocoa通过Reactive magic扩展了Cocoa API)。 ReactiveX简化了异步调用(避免了回调地狱 ),使代码更具功能性,可读性且不易出错。 我们主要将其用于API调用和用户界面绑定。 有关为什么使用Rx的更多信息,请查看RxSwift不错的页面。 Ray Wenderlich有一个很好的Rx入门教程。 SwiftyJSON 尽管Swift对JSON有一些基本的了解,但是使用SwiftyJSON可以使代码更整洁,类型更强,代码更短,更好理解。 翠鸟 有很多用于缓存图像的库,但是我们发现Kingfisher是最简单,最方便的使用方法。 PureLayout AutoLayout在情节提要板上可以很好地工作,但是如果您想在代码中添加布局约束,则原始API相当冗长且难以阅读。 PureLayout是一个很好的API,可以解决此问题。 凭借其方便的类型推断,尤其是使用Swift的短点语法,PureLayout的工作非常简洁。 SnapKit是一个不错的选择,我们尚未尝试。 […]

使用MVVM和RxSwift构建您的第一个应用程序

简介: 在本文中,我们将分四个部分逐步构建您的第一个Set应用程序。 第一部分将向您介绍MVVM应用程序体系结构。 第二部分将演示SetSDK设置过程。 第三部分将应用MVVM概念来为您的应用程序创建支架。 最后,在第四部分中,我们将使用SetSDK全天实时显示出发地和预计的目的地。 可以从Set Gitlab存储库下载该项目的源代码。 Set SDK允许任何开发人员通过简单的pod install将机器学习和用户行为预测集成到他们自己的应用程序中。 SDK的第一个版本侧重于用户位置,回答了以下问题:他们现在在哪里,下一步要去哪里? 我想提供一个简单的演示应用程序,以演示如何将SDK集成到您自己的项目中以及如何使用SDK的某些功能。 在我讲的时候,我将使用Apple的MVC(模型视图控制器)体系结构,MVVM(模型视图视图模型)和一种启用MVVM的技术(称为RxSwift)来替代它。 第一部分:MVVM概述 关于MVC设计模式为何变得令人头疼的信息很多,尤其是在更复杂的应用程序中。 MVC对视图控制器负有太多责任。 关注点很少。 在下图中,您将看到视图和模型主要只是存在而无需做任何事情,而视图控制器则负责更新和接收来自模型和视图的更新以及所有业务逻辑,数据库访问,联网等。 在复杂的应用程序中,视图控制器可能会增长为成千上万行代码,并且很难维护。 MVVM是对MVC的简单添加,它简化了视图控制器的作用: 对于您应用中的每个屏幕或视图控制器,我们都会引入一个附加文件,即视图模型。 视图模型负责与模型数据进行交互,并将业务逻辑和显示格式应用于该数据。 视图模型还可以利用数据库或网络抽象。 格式化的数据通常通过简单的属性,RxSwift Observable或类似的技术(稍后会详细介绍)提供给应用程序的视图层。 视图控制器的新角色是通常使用RxSwift之类的工具简单地将视图模型公开的数据“绑定”到视图。 视图控制器还处理诸如按钮轻击和手势之类的用户交互,将这些事件通知视图模型。 这样,视图和视图模型紧密耦合,可以视为单个功能单元。 MVVM可以使关注点更加清晰。 它从视图层中删除了业务逻辑和数据格式,并创建了易于通过单元测试进行测试的视图模型。 可以以“无头”方式(没有任何视图)测试许多应用程序,而可以使用更合适的工具(例如Xcode UI测试)来测试视图。 这样就导致了具有更少错误的应用程序,更易于维护。 第二部分 启动SetSDK应用 要启动SetSDK,您将需要应用程序的客户端凭据。 我们目前正在使用一个自助服务开发人员门户网站,您可以在其中创建这些凭据,但是现在发送电子邮件至sander@set.gl,您将通过电子邮件接收凭据。 SetSDK使用Cocoapods分发。 如果您不熟悉它,请访问他们的网站,其中有许多很好的入门指南。 使用File > New > Project… > Single View Application创建一个新的Xcode项目。 我叫我的MVVMSetSDK。 创建项目后,将其关闭并在命令行上导航到项目的根目录。 通过运行pod init初始化Cocoapods。 打开新创建的Podfile进行编辑,并向其中添加SetSDK依赖项: 并提供当我们要求使用他们的位置和运动数据时显示给用户的Info.plist字符串。 […]

iOSをMVC,MVP,MVVM,清洁架构で実装してみた

何番煎じだよって感じですが,アーキテクチャに対する考チャに対する方は割と正解がなくて,自分の中に一つ落とし込んでおいて损はないと感じたため,补充という形で记事にさせていただきます。 アーキテクチャとは? 一言でいうと, アプリケーションを绮丽丽装するための设计方法! アーキテクチャを考虑しない设计でコードを书いていると以下のようなスにぶち当たります。 一つのクラスの肥大化(iOSで言うところのFatViewController) ロジックが烦雑になる 同じ处理を使い回せない チーム开発で役割分担しにくい テストがしにくい 属人化が进み,引き継ぎが难しくなる 机能の追加,修正が困难 等等… 正直まだまだあるとは思いますが,とにかく设计はこだわってないと后で地狱を见るということさえ伝わればOKです。 示例应用 アーキテクチャを语る上で叩き台にするアプリがいるなーと思ったので作りました。 阅覧するときは,见たいアーキテクチャのチャランチ(master / mvc / mvp / mvvm / clean-architecture / clearn-architecture + mvvm)に切り変えてください。 https://github.com/rockname/ArchitectureSampleWithFirebase Firebaseでユーザーの登录/登录,投稿のCRUD处理をする,ものすごくシンプルなアプリです。 FatViewController ブアーキテクチャのない世界をみなさんにはお见せしましょう。(ブランチはmasterです) 投稿一覧シーンであるListViewControllerを见てもらうとわかりますが,こんなに単纯なアプリにもかかわらずすでにコードが123行あります。 ViewControllerがすべての役割を担わされていることがわかりますね。 非常に胖な状态です。 役割 ViewController UIのレイアウト UIの更新 ユーザーのアクション通知 データの处理 データの更新通知 ビジネスロジック 评価 いいところ🙆‍ 思考停止でコーディングできる(これはいいところなのか…?) UIKitの恩恵を最大に享受できる 悪いところ🙅‍ それ以外すべて 模型视图控制器(MVC) Webアプリケーションフレームワークでよく闻くやつですね。 Appleの公式ドキュメントでもiOSアプリ开発はMVCが一般的みたいな书き方がされています。 https://developer.apple.com/jp/documentation/CocoaEncyclopedia.pdf しかし,iOSのUIフレームワークであるUIKitはViewとControllerが密接に系がっており(ViewControllerというクラスがあるくらい),iOSのMVCはよくMassiveViewControllerだなんて皮肉を言われています。。 […]

使用Swift 3的IOS中的MVVM

当我们为最新的iOS应用程序奠定基础时,想向我们以前的iOS应用程序学习。 我们设定了两个目标: 避免Massive View Controller综合症 尽可能少的重复代码 iOS中的MVVM 自从最近出现更好的架构模式以来,MVC(模型视图控制器)设计模式就已经失去了其作为实际模式的地位。 现在,MVC被臭名昭著地称为Massive(或Messy)-View-Controller模式,其原因是在View控制器中堆积1000行以上的代码非常容易。 甚至苹果公司也以避开其示例代码中的MVC模式而闻名。 MVVM(模型-视图-视图模型)是一种体系结构模式,是MVC的替代方案,它可以使将ViewController的UI特定职责进一步隔离到视图模型变得更加容易。 在MVVM设计模式中, 模型与在MVC模式中相同,它表示简单数据。 视图由UIView或UIViewController对象以及它们的.storyboard和.storyboard文件表示,它们仅应显示准备好的数据。 ViewModel隐藏所有异步联网代码,用于可视表示的数据准备代码以及用于侦听Model更改的代码。 所有这些都隐藏在精心定义的API后面,该API建模为适合该特定View 。 使用MVVM的好处之一是测试,您可以在单元测试中更轻松地对其进行测试,而不会影响UI代码。 现在, 视图 ( UIViewController / UIView )变得更加简单,而ViewModel充当Model和View之间的粘合剂 。 在iOS Swift3中应用MVVM 如果您不熟悉MVVM,并且想深入了解如何在应用程序中实现和使用MVVM设计模式,请深入阅读本文,并附带示例示例。 我们将在此示例上演示iOS MVVM模式的用法。 简短地说,该应用程序显示一个用户列表,每个列表包含一个用户图像,其名称和电子邮件。 示例项目中使用的库: Alamofire:是一个用Swift(版本4.4)编写的HTTP网络库。 SDWebImage:该库提供了具有缓存支持的异步图像下载器。 Mapper:是一个简单的Swift库,用于将JSON转换为强类型对象。 步骤1:设定APIClient RANDOM USER GENERATOR使用的API,不需要密钥和授权令牌。端点是:http://api.randomuser.me/?results=10&nat=e 我编写了一个具有完成处理程序的downloadUser函数 。 JSON数据将以字典数组的形式返回,用于下面的关键“结果”。 步骤2:设置ViewModel。 #1:我创建了从NSObject继承的UserViewModel文件。 这将是我的View Controller中的属性,并由情节提要注入。 #2创建一个标记为@IBOutlet的apiClient属性,该属性将由情节提要实例化。 因为我知道情节提要将注入它,所以我可以使用(!)bang运算符,因为我知道它不会为零。 第3步:设置视图控制器。 用@IBOutlet声明UserViewModel属性,情节提要将实例化此ViewModel对象。 ViewDidAppear:在视图出现后调用-是使用userViewModel属性从API开始加载用户的好地方。 从API下载数据后,重新加载tableView以显示我们检索到的应用程序对象。 步骤4:如何使用情节提要定义Object属性。 从对象库中,将一个对象项目拖到视图控制器上,并将其插入VC的顶部。 […]

RxSwift世界中的ViewModel

牢记这一点,我想将ViewModel视为一个“黑匣子”,它接受一些UI触发器(按钮点击,表视图选择,文本编辑事件等),其他依赖项(NeworkService,DataBaseService,LocationService)并应用一些Rx运算符(确定业务逻辑)。 然后,从视图模型中,您可以获取转换后的可观察对象,并将其绑定回您的UI以应用您的业务逻辑。 作为示例,我想展示如何实现可搜索数据列表,并在带有搜索栏的表格视图中显示它 假设所有实现模型的人员都要做的就是创建ViewModel和ViewController 因此,让我们定义UI触发器: 搜索触发器(用户可以键入以搜索列表中的数据) 滚动触发器(用户可以滚动以从列表中提取新数据) 现在我们可以定义ViewModel接口 现在让我们定义要应用于初始触发器的转换 从搜索查询转换为请求 防止触发空查询请求 防止用户每次输入新字符时发出火灾指令 取消先前的请求以支持新请求 每次用户滚动到滚动视图的底部边缘时都命中请求 用新数据附加先前状态(数组) 实施转换: 过滤空字符串,请记住我们不要触发空查询的请求 防止用户每次输入新字符时触发请求,仅在暂停0.3秒时才触发 将搜索查询转换为请求并取消之前的查询 将英雄转变为 虚拟HeroCellData (例如标题,图像网址) 将HeroCellData数组转换为HeroCellSection (这需要将其绑定到UITableView) 触发下一页请求 现在让我们将转换后的Observable绑定回UI 创建ViewModel 将主表项绑定到UITableView 将搜索项绑定到UISearchController的tableView 摘要: 我们的视图模型是“纯”的,它是不可变的,我们甚至不需要在ViewController中对其进行引用( disposeBag使订阅保持活动状态) 所有逻辑封装在一个地方 可以使用RxTests轻松测试它。 在下一篇文章中🙂 进一步阅读: Rx简介 RxSwift书 Rx.io RxDataSources 原始码 快乐的RxSwift编码! 🙂

带有RxSwift的MVVM登录屏幕

如何将MVVM用于与RxSwift绑定的经典登录屏幕? 这就是我们的方法..(歌曲♩♪♫♬) 让我们玩! ..但首先,什么是MVVM? 你应该在这里看看.. Swift中的MVVM – Artsy Engineering 模型视图ViewModel已成为我在iOS上编写应用程序的默认方式–它使编写iOS应用程序变得很有趣。 我写了…… artsy.github.io 对于RxSwift? 您应该在这里找到所有提示和技巧https://github.com/ReactiveX/RxSwift 所有我们需要的.. 6个步骤 .. !! 现在..让我们开始: 1-模型 我们创建一个使用用户名和密码登录的模型 然后,我们需要创建将处理此模型的viewModel .. 2-FieldViewModel 我们定义此协议VSFieldViewModel来表示条目数据字段(在我们的示例中,我们有emailField和passwordField) 我们使用一些属性来描述字段,例如title和errorMessage 然后,我们定义observables( 变量值:Variable )以在需要时处理和更新用户界面,在本例中,字段值和errorMessage是稍后绑定的变量。 我们定义一个validate()函数来使用定义的模式来validate()数据 我们添加扩展名,以使用一些实用程序方法来调整字符串或有效模式的有效大小(以后用于有效的密码和电子邮件输入值) 3-密码字段viewModel 除了基本的FieldViewModel外,我们还添加了另一个协议以自定义密码输入的类型(安全文本) viewModel定义validate()方法(字符串输入stize) 我们对下一个viewModel进行相同操作。 4-电子邮件字段viewModel 这里的viewModel定义变量和自定义模式以验证输入值(电子邮件模式格式:xx@xx.xx) 如您所见,某些变量可以为空(甚至为nil),例如errorMessage ,该条目应在无效输入后进行更新 现在..我们应该创建我们的控制器viewModel,它将处理下面的这些字段。 5-登录视图模型 在这个viewModel中,我们将model emailFieldViewModel用来处理电子邮件数据的字段 passwordFieldViewModel用于处理密码数据的字段 validForm()验证所有输入数据 disposeBag附带的disposeBag来管理内存 isLoading isSuccess和errorMessage是由控制器管理并用于绑定UI的变量RxSwift 用于调用身份验证服务的signin()方法 我们从viewModel字段使用模型电子邮件和密码提出了请求 我们在响应时更新可观察对象以处理UI,首先更新isLoading状态,然后在成功更新isSuccess状态时更新 相同的错误时,我们将错误消息放在errorMessage 6-最后! 控制器 ViewController将配置UI和viewModel之间的绑定 […]