iOS ReactiveCocoa MVVM

学习了在MVVM中如何使用RactiveCocoa,简单的写上一个demo。重点在于如何在MVVM各层之间使用RAC的信号来更方便的在各个层之间进行响应式数据交互。
demo需求:一个登录界面(登录界面只有账号和密码都有输入,登录按钮才可以点击操作),一个登录成功后跳转展示界面。
在这里插入图片描述
ViewModel中是负责登录的业务逻辑层,该层中负责数据验证,网络请求,数据存储等一些和ui无关的业务逻辑。
在这里插入图片描述
因为ViewModel层是独立于UI层而存在的,所以可以在没有UI的情况下我们就可以去实现相应模块的ViewModel层。这正好减少了个个层次间的耦合性,同时也提高了可测试性,总体上改善了可维护性。好废话少说,接下来要实现登录的Model层。

//
//  User.h
//  RACDemo
//
//  Created by johnny on 2024/6/5.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface User : NSObject

@property (nonatomic, copy) NSString *name;

@property (nonatomic, copy) NSString *pwd;

@end

NS_ASSUME_NONNULL_END

接下来要实现登录的ViewModel层。

//
//  UserViewModel.h
//  RACDemo
//
//  Created by johnny on 2024/6/5.
//

#import <Foundation/Foundation.h>
#import "ReactiveObjC.h"
#import "User.h"

NS_ASSUME_NONNULL_BEGIN

@interface UserViewModel : NSObject

@property (nonatomic, strong) User *user;

// 登录成功
@property (nonatomic, strong) RACSubject *successObject;

// 认证失败
@property (nonatomic, strong) RACSubject *failObject;

// 登录失败
@property (nonatomic, strong) RACSubject *errorObject;

// 登录按钮是否可用
- (id)loginBtnIsValid;

// 登录
-(void)login;

@end

NS_ASSUME_NONNULL_END

登录ViewModel层对应的类的头文件中内容如上所示。其实上面一些常用的信号可以抽象出来放到ViewModel的父类中。属性user是用来绑定用户输入的用户名和密码。上面三个定义信号successObject,failObject,errorObject用来发送网络请求的数据。

successObject 负责处理网络请求成功且符合正常业务逻辑事件。
failObject 负责处理网络请求成功不符合正常业务逻辑的处理
errorObject 负责处理网络异常处理。
结合项目中的实例来解释一下什么时候发送successObject信号,如何发送failureObject信号,何时使用errorObject信号。
以某些理财App中购买理财产品的业务流程为例。在用户下单之前先去判断用户是否实名认证以及绑定银行卡,如果用户已经实名和绑定银行卡就走正常支付流程(用户就是想去下单购买),VM就往VC发送successObject信号,当前VC就会根据信号的指示跳转到下单支付页面。 但是如果用户没有实名或者绑卡,那么VM就给VC发送failureObject信号,根据信号中的参数来判断是走实名认证流程还是走绑定银行卡流程。 errorObject就比较简单了,网络异常,后台服务器抛出的异常等不需要iOS这边做业务逻辑处理的,就放在errorObject中负责错误信息的展示。

文字说完了,如果有些小伙伴还不太明白,那看下面这张原理图吧。把三种信号我们可以类比成十字路口的红绿灯。successObject就是绿灯,可以走正常流程。failureObject是黄灯,先等一下,完成该做的就可以走绿灯了。而errorObject就是一红灯,报错异常,终止业务流程并提升错误信息。有图有真相,到这儿如果还不理解我就没招了。
在这里插入图片描述
备注:借用的图片
在Public方法中- (id) buttonIsValid; 负责返回登录按钮是否可用的信号。- (void)login;发起网络请求,调用登录网络接口。

//
//  UserViewModel.m
//  RACDemo
//
//  Created by johnny on 2024/6/5.
//

#import "UserViewModel.h"


@interface UserViewModel ()

@property (nonatomic, strong)RACSignal *userNameSignal;
@property (nonatomic, strong)RACSignal *pswSignal;

@property (nonatomic, strong) NSArray *requestData;

@end

@implementation UserViewModel

-(User *)user {
    if (_user == nil) {
        _user = [[User alloc]init];
    }
    return _user;
}
// VCViewModel的初始化方法如下,负责初始化属性
-(instancetype)init {
    if (self= [super init]) {
        [self initialize];
    }
    return self;
}


- (void)initialize {
    _userNameSignal = RACObserve(self, self.user.name);
    _pswSignal = RACObserve(self, self.user.pwd);
    
    // 初始化 success
    _successObject = [RACSubject subject];
    _failObject = [RACSubject subject];
    _errorObject = [RACSubject subject];
}

// 合并两个输入框信号,并返回按钮bool类型的值
-(id)loginBtnIsValid {
   RACSignal *isValid = [RACSignal combineLatest:@[_userNameSignal, _pswSignal] reduce:^id (NSString *user, NSString *psw){
        return @(user.length > 3 && psw.length > 3);
    }];
    return isValid;
}

// 模拟网络请求的发送,并发出网络请求成功的信号
-(void)login {
    // 网络请求
    _requestData = @[_user.name, _user.pwd];
    
    NSLog(@"网络请求");
    
    // 成功发送信号
    [_successObject sendNext:_requestData];
    
    [_failObject sendNext:@"认证失败"];
    
    [_errorObject sendNext:@"登录失败"];
}


@end

上面是VM的实现,如果要进行单元测试的话,就对相应的VM类进行初始化,调用相应的函数进行单元测试即可。接着就是看如何在相应的VC模块中使用VM。

剩下的就是在VC中实例化响应的VM类。

//
//  LoginViewController.m
//  RACDemo
//
//  Created by johnny on 2024/6/5.
//

#import "LoginViewController.h"
#import "ReactiveObjC.h"
#import "UserViewModel.h"


@interface LoginViewController ()

@property (nonatomic, strong) UITextField *accountField;
@property (nonatomic, strong) UITextField *pwdField;
@property (nonatomic, strong) UIButton *loginBtn;

@property (nonatomic, strong) UserViewModel *viewModel;

@end

@implementation LoginViewController

-(UserViewModel *)viewModel {
    if (_viewModel == nil) {
        _viewModel = [[UserViewModel alloc]init];
    }
    return _viewModel;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor yellowColor];
    
    [self setUP];
    
    [self bindViewModel];
    
    //按钮点击事件
    @weakify(self);
    [[self.loginBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        NSLog(@"点击登录按钮");
        @strongify(self);
        [self.viewModel login];
    }];
    
    //登录成功要处理的方法
    [_viewModel.successObject subscribeNext:^(id  _Nullable x) {
        NSLog(@"successObject %@", x);
    }];
    
    //fail
    [_viewModel.failObject subscribeNext:^(id  _Nullable x) {
        NSLog(@"failObject %@", x);
    }];
    //error
    [_viewModel.errorObject subscribeNext:^(id  _Nullable x) {
        NSLog(@"errorObject %@", x);
    }];
}

//关联ViewModel
- (void)bindViewModel {
    RAC(self.viewModel.user, name) = _accountField.rac_textSignal;
    RAC(self.viewModel.user, pwd) = _pwdField.rac_textSignal;
    RAC(self.loginBtn, enabled) = _viewModel.loginBtnIsValid;
    
    [_viewModel.loginBtnIsValid subscribeNext:^(id  _Nullable x) {
        NSLog(@"loginBtnIsValid %@", x);
        self.loginBtn.backgroundColor = [UIColor systemPinkColor];
    }];
}

- (void)setUP {
    self.accountField = [[UITextField alloc]initWithFrame:CGRectMake(100, 100, 200, 40)];
    self.accountField.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.accountField];
    
    self.pwdField = [[UITextField alloc]initWithFrame:CGRectMake(100, 160, 200, 40)];
    self.pwdField.backgroundColor = [UIColor greenColor];
    [self.view addSubview:self.pwdField];
    
    self.loginBtn = [[UIButton alloc]initWithFrame:CGRectMake(100, 400, 50, 50)];
    self.loginBtn.backgroundColor = [UIColor blackColor];
    [self.view addSubview:self.loginBtn];
}


@end

到此为止,一个完整模拟登录模块的RAC下的MVVM就实现完毕。

 platform :ios, '12.0'
 

target 'RACDemo' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

 pod 'ReactiveObjC'
 pod 'ReactiveCocoa'


end

post_install do |installer|
  
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['ENABLE_BITCODE'] = 'NO'
      # Xcode 14 以后 bundle 需要需要签名
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '10.0'
#      config.build_settings['EXPANDED_CODE_SIGN_IDENTITY'] = ""
      config.build_settings['CODE_SIGNING_REQUIRED'] = "NO"
      config.build_settings['CODE_SIGNING_ALLOWED'] = "NO"

    end
  end
end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/710526.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【linux】应用程序访问百度时,操作系统内核网络接口日志

代码合入&#xff1a; 登录 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/commit/c639573cc7c4984913d4a89884347e5a30a51eac 启动操作系统运行dmesg的日志像这样&#xff1a; dmesg_log/2024_06_14_00_40_54.txt r77683962/linux-6.9.0 - Gitee.com 注意&#xf…

C语言小例程20/100

题目&#xff1a;一个数如果恰好等于它的因子之和&#xff0c;这个数就称为"完数"。例如61&#xff0b;2&#xff0b;3.编程找出1000以内的所有完数。 #include<stdio.h> #define N 1000 int main() {int i,j,k,n,sum;int a[256];for(i2;i<N;i){suma[0]1;k…

Nintex流程平台引入生成式人工智能,实现自动化革新

工作流自动化提供商Nintex宣布在其Nintex流程平台上推出一系列新的人工智能驱动改进。这些增强显著减少了文档化、管理和自动化业务流程所需的时间。这些新特性为Nintex流程平台不断扩展的人工智能能力增添了新的亮点。 Nintex首席产品官Niranjan Vijayaragavan表示&#xff1a…

阿里新发布的UniAnimate现高效人像动画生成;在ComfyUI中使用Stable 3模型;音频版的gpt2o;将 PDF 文档转换为音频播客

✨ 1: UniAnimate 阿里新发布的UniAnimate通过统一的视频扩散模型&#xff0c;实现高效人像动画生成&#xff0c;支持长视频生成 UniAnimate 是一种专注于一致性人像动画生成的统一视频扩散模型。该模型通过映射参考图像、姿势指导和噪声视频到一个共同特征空间&#xff0c;实…

SSM家乡旅游网-计算机毕业设计源码04802

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;SSM家乡旅游网当然也不能排除在外。SSM家乡旅游网是以实际运用为开发背景&#xff0c;运用软件工程开发方法&#xff0c…

Django配置连接池:使用django-db-connection-pool配置连接池

一、该三方库文档使用 github地址&#xff1a; https://github.com/altairbow/django-db-connection-pool/blob/1.2.5/README_CN.mdhttps://github.com/altairbow/django-db-connection-pool/blob/1.2.5/README_CN.md1、选择指定版本&#xff0c;查看指定版本的文档和配置&am…

Xcode无法使用设备:Failed to prepare the device for development

问题&#xff1a; Xcode无法使用设备开发&#xff0c;失败报错如下&#xff1a; Failed to prepare the device for development. This operation can fail if the version of the OS on the device is incompatible with the installed version of Xcode. You may also need…

容性负载箱在电子元器件制造中的应用有哪些?

容性负载箱是一种能够模拟实际负载的电子设备&#xff0c;主要用于测试电源、变频器、逆变器等电力电子设备的性能。在电子元器件制造中&#xff0c;容性负载箱的应用非常广泛&#xff0c;主要体现在以下几个方面&#xff1a; 1. 电源测试&#xff1a;电源是电子元器件正常工作…

【触想智能】壁挂式工业一体机在智能制造行业上的应用分析

随着智能制造的兴起&#xff0c;壁挂式工业一体机成为了越来越多工厂的首选设备。壁挂式工业一体机是一种高性能的计算机&#xff0c;内置多种工业级传感器和执行器&#xff0c;可以实时获取工厂生产过程中的各种数据&#xff0c;并与其他设备进行无缝连接。 为了大家更深入的了…

自动生成企业培训视频:创新与效率的完美结合

前言 随着人工智能技术的飞速发展&#xff0c;大模型技术在各个领域的应用日益广泛。在企业培训领域&#xff0c;大模型技术的应用为培训视频的生成带来了革命性的变革。本文将探讨如何利用大模型技术自动生成企业培训视频&#xff0c;以及这一技术为企业培训带来的创新和效率…

停止游戏中的循环扣血显示

停止游戏中循环扣血并显示的具体实现方式会依赖于你的代码结构和游戏的逻辑。通常情况下&#xff0c;你可以通过以下方式来实现停止循环扣血和显示&#xff1a; 1、问题背景 在使用 Python 代码为游戏开发一个生命值条时&#xff0c;遇到了一个问题。代码使用了循环来减少生命…

Mysql之不使用部署在k8s集群的Mysql而是选择单独部署的Mysql的原因

测试准备&#xff1a; 线程组&#xff1a;并发数100&#xff0c;持续时间2min 两个请求&#xff1a;使用k8s集群中的mysql的wordpress对应端口30011 使用单独部署的mysql的wordpress的对应端口为30022 访问同一个博客 测试结果&#xff1a; 汇总报告&#xff1a; 响应时间图&…

DevOps学习回顾01-技能发展路线-岗位能力-体系认知(射箭和拉弓的区别)

事为先&#xff0c;人为重–事在人为 参考来源&#xff1a; 极客时间专栏&#xff1a;DevOps实战笔记&#xff0c;作者&#xff1a;石雪峰 课程链接&#xff1a;https://time.geekbang.org/column/intro/235 时代的典型特征 VUCA VUCA 是指易变性&#xff08;Volatility&…

深度学习 - CNN

第一部分&#xff1a;基础知识 1. 什么是卷积神经网络&#xff08;CNN&#xff09; 定义和基本概念 卷积神经网络&#xff08;CNN&#xff09;是一种专门用于处理具有网格结构数据&#xff08;如图像&#xff09;的深度学习模型。它们在图像识别和计算机视觉领域表现尤为突出…

欢乐钓鱼大师通关必备秘籍!云手机游戏辅助!

《欢乐钓鱼大师》是一款让玩家沉浸在放松钓鱼乐趣中的手机游戏。不同于传统钓鱼游戏&#xff0c;它融合了收集、升级和竞技等元素&#xff0c;让每位玩家可以根据自己的喜好和目标来发展钓鱼技艺。本攻略将为您详细介绍如何在游戏中迅速提升实力&#xff0c;达到通关的最高境界…

idea Alt+/ 自动补全变量名开头是大写 改 选择小写开头变量名

idea 中自动补全变量名是非常常见的操作&#xff0c;变量名一般都需要小写开头&#xff0c;但是idea中 Alt / 自动补全变量名时 补全的变量名是大写的&#xff0c;这就很难受了。如下图所示&#xff1a; AutowiredLogService LogService;Ctrl 空格 快捷键 虽然不像 Alt / 一…

基于51单片机的智能语音电子秤设计

一.硬件方案 电子秤的测量原理是被称量物体的重量使传感器弹性体发生变形&#xff0c;输出与重量成正比的电信号&#xff0c;传感器输出信号经放大器放大后&#xff0c;输入转换器进行转换&#xff0c;转换成的频率信号直接送入微处理器中&#xff0c;其数字量由微机进行处理&…

PMS助力制造企业高效运营︱PMO大会

全国PMO专业人士年度盛会 北京易贝恩项目管理科技有限公司副总经理朱洪泽女士受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“PMS助力制造企业高效运营”。大会将于6月29-30日在北京举办&#xff0c;敬请关注&#xff01; 议题简要&#xff1a; …

【Better Lighting V2】Blender商城10周年免费送插件灯光预设和图案轮库场景打光和模拟光透过图案水滴波纹效果

Blender商城10周年免费送插件&#xff1a;https://blendermarket.com/birthday Better Lighting V2 灯光预设和图案轮库 模拟各种环境下光线透过物体效果 各种预设快速调整 非常简单和快速打光调色 更多详细介绍&#xff1a;https://blendermarket.com/products/bette…

基于python_CNN的人体姿态行为识别-含数据集+pyqt界面

代码下载地址&#xff1a; https://download.csdn.net/download/qq_34904125/89383060 本代码是基于python pytorch环境安装的。 下载本代码后&#xff0c;有个requirement.txt文本&#xff0c;里面介绍了如何安装环境&#xff0c;环境需要自行配置。 或可直接参考下面博文…