viewModel 代码
@interface ZJEditProfileViewModel : NSObject
@property (nonatomic, copy) NSString *strNickName;
@property (nonatomic, copy) NSString *strNickNameFlag;
@property (nonatomic, strong) RACSignal *btnEnableSignal;
@property (nonatomic, strong) RACCommand *saveCommand;
@end
@implementation ZJEditProfileViewModel
- (instancetype)init
{
self = [super init];
if (self) {
[self setUp];
}
return self;
}
- (void)setUp{
@weakify(self);
_btnEnableSignal = [RACSignal combineLatest:@[RACObserve(self,strNickName)] reduce:^id _Nullable(NSString *nickName){
return @(nickName.length > 1);
}];
_saveCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
@strongify(self);
return [RACSignal createSignal:^RACDisposable * _Nullable(id _Nonnull subscriber) {
@strongify(self);
NSString *registerAccount = [[tztUserSaveDataObj getShareInstance] getUserDataValueForKey:zt_key_internetAccount_regcust_id];
NSDictionary *userInfo = (NSDictionary *)[[tztUserSaveDataObj getShareInstance] getUserDataObjectForKey:zt_key_internetAccount_userinfo] ?: @{};
NSMutableDictionary *custInfo = userInfo.mutableCopy;
[custInfo setObject:JTSafeString(self.strNickName) forKey:@"nick_name"];
NSDictionary *params = @{ @"regcust_id" : JTSafeString(registerAccount),
@"cust_info" : custInfo};
[[ZJAppService.loginService.api requestForChangeNickName:params] subscribeNext:^(id tuple) {
RACTupleUnpack(NSNumber *bSuccess, JTResponseModel *response, NSError *error) = tuple;
if ([bSuccess boolValue]) {
if (!error && response.ret == 0) {
[subscriber sendNext:@"请求成功"];
NSMutableDictionary *dicUserInfo = (NSMutableDictionary *)[[tztUserSaveDataObj getShareInstance] getUserDataObjectForKey:zt_key_internetAccount_userinfo].mutableCopy;
[dicUserInfo setTztValue:self.strNickName ?: @"尊敬的客户" forKey:@"nick_name"];
[[tztUserSaveDataObj getShareInstance] setUserDataObject:dicUserInfo ForKey:zt_key_internetAccount_userinfo];
NSString *strInfo = [[tztUserSaveDataObj getShareInstance] getUserDataValueForKey:zt_key_internetAccount_info];
NSArray *arrayInfo = [strInfo mj_JSONObject];
if ([arrayInfo isKindOfClass:NSArray.class] && arrayInfo.count) {
NSMutableDictionary *dictInfo = [arrayInfo.firstObject mutableCopy];
[dictInfo tztSetObject:dicUserInfo forKey:@"user_info"];
[[tztUserSaveDataObj getShareInstance] setUserDataObject:[@[dictInfo ?: @{}] mj_JSONString] ForKey:zt_key_internetAccount_info];
}
} else {
JTSHOW_TIPS(response.errorMsg ?: @"网络错误,请重试");
}
} else {
JTSHOW_TIPS(@"网络错误,请重试");
}
[subscriber sendCompleted];
}];
return [RACDisposable disposableWithBlock:^{
}];
}];
}];
}
@end
VC代码
/// Lazy Methods
- (ZJEditProfileViewModel *)viewModel {
if (!_viewModel) {
_viewModel = [ZJEditProfileViewModel new];
}
return _viewModel;
}
-(UIView *)headerView
{
if (_headerView == NULL) {
_headerView = [[UIView alloc] init];
_headerView.backgroundColor = (g_nSkinType == tztSkin_White) ? [UIColor whiteColor] : [UIColor colorWithTztRGBStr:@"36,40,58"];
}
return _headerView;
}
-(UILabel *)labTitle
{
if (_labTitle == NULL) {
_labTitle = [[UILabel alloc] init];
_labTitle.backgroundColor = [UIColor clearColor];
_labTitle.text = @"昵称";
_labTitle.font = [UIFont PingFang:regular FontSize:16];
_labTitle.textColor = (g_nSkinType == tztSkin_White) ? [UIColor blackColor] : [UIColor colorWithTztRGBStr:@"219,219,219"];
}
return _labTitle;
}
- (UITextField *)textFieldNickName
{
if (_textFieldNickName == NULL) {
_textFieldNickName = [[UITextField alloc] init];
_textFieldNickName.borderStyle = UITextBorderStyleNone;
_textFieldNickName.secureTextEntry = NO;
_textFieldNickName.keyboardType = UIKeyboardTypeDefault;
_textFieldNickName.textAlignment = NSTextAlignmentRight;
_textFieldNickName.textColor = (g_nSkinType == tztSkin_White) ? [UIColor blackColor] : [UIColor colorWithTztRGBStr:@"219,219,219"];
_textFieldNickName.tintColor = [UIColor colorWithRGBULong:0xD9AD77];
_textFieldNickName.font = [UIFont PingFang:regular FontSize:16];
_textFieldNickName.keyboardAppearance = (g_nSkinType == tztSkin_White) ? UIKeyboardAppearanceLight : UIKeyboardAppearanceDark;
_textFieldNickName.delegate = self;
if (self.model.title.length >= 8) {
_textFieldNickName.text = [self.model.title substringToIndex:8];
}else {
_textFieldNickName.text = self.model.title;
}
self.viewModel.strNickNameFlag = _textFieldNickName.text;
}
return _textFieldNickName;
}
-(UILabel *)lbPrompt
{
if (_lbPrompt == NULL) {
_lbPrompt = [[UILabel alloc] init];
_lbPrompt.backgroundColor = [UIColor clearColor];
_lbPrompt.font = [UIFont PingFang:regular FontSize:14];
_lbPrompt.text = @"2-8个字符,支持中文、英文或数字";
_lbPrompt.textColor = (g_nSkinType == tztSkin_White) ? [UIColor colorWithRGBULong:0x999999] : [UIColor colorWithTztRGBStr:@"98,98,98"];
}
return _lbPrompt;
}
- (UIButton *)btnSave
{
if (_btnSave == NULL) {
_btnSave= [UIButton buttonWithType:UIButtonTypeCustom];
[_btnSave.titleLabel setFont:[UIFont PingFang:regular FontSize:16]];
[_btnSave setBackgroundImage:[UIImage imageNamed:@"jt_phonelogin_jg_submit"] forState:UIControlStateNormal];
[_btnSave setBackgroundImage: (g_nSkinType == tztSkin_White) ? [UIImage imageNamed:@"jt_phonelogin_jg_submit_disable"] : [UIImage imageNamed:@"jt_phonelogin_jg_submit_black_disable"] forState:UIControlStateDisabled];
[_btnSave setBackgroundImage:[UIImage imageNamed:@"jt_phonelogin_jg_submit_highlighted"] forState:UIControlStateHighlighted];
[_btnSave setTitleColor:[UIColor colorWithRed:97 / 255.0 green:63 / 255.0 blue:26 / 255.0 alpha:1.0] forState:UIControlStateNormal];
[_btnSave setTitleColor: (g_nSkinType == tztSkin_White) ? [UIColor colorWithRed:97 / 255.0 green:63 / 255.0 blue:26 / 255.0 alpha:0.3] : [UIColor colorWithRed:97 / 255.0 green:63 / 255.0 blue:26 / 255.0 alpha:1.0]forState:UIControlStateDisabled];
[_btnSave setTitle:@"保存" forState:UIControlStateNormal];
}
return _btnSave;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self addSubviews];
[self addConstraints];
[self loginEvent];
[self bindData];
}
- (RACSubject *)setData:(ZJAccountManageModel *)data {
self.model = data;
return nil;
}
/// 组装视图
- (void)addSubviews {
[self.view addSubview:self.headerView];
[self.headerView addSubview:self.labTitle];
[self.headerView addSubview:self.textFieldNickName];
[self.view addSubview:self.lbPrompt];
[self.view addSubview:self.btnSave];
}
/// 添加约束
- (void)addConstraints {
[self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.tztTitleView.mas_bottom).offset(8);
make.left.right.equalTo(self.view);
make.height.mas_equalTo(50);
}];
[self.labTitle mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.headerView).offset(20);
make.size.mas_equalTo(CGSizeMake(32, 50));
make.top.equalTo(self.headerView);
}];
[self.textFieldNickName mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.headerView).offset(-20);
make.left.equalTo(self.labTitle.mas_right);
make.top.equalTo(self.headerView);
make.height.mas_equalTo(50);
}];
[self.lbPrompt mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view).offset(20);
make.top.equalTo(self.headerView.mas_bottom).offset(8);
}];
[self.btnSave mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.lbPrompt.mas_bottom).offset(26);
make.right.equalTo(self.view).offset(-20);
make.left.equalTo(self.view).offset(20);
make.height.mas_equalTo(50);
}];
}
/// 建立绑定
- (void)bindData {
RAC(self.viewModel,strNickName) = self.textFieldNickName.rac_textSignal;
RAC(self.btnSave,enabled) = self.viewModel.btnEnableSignal;
}
- (void)loginEvent {
@weakify(self);
[[self.textFieldNickName.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
@strongify(self)
if (self.textFieldNickName.text.length > 8) {
self.textFieldNickName.text = [self.textFieldNickName.text substringToIndex:8];
}
return value.length <= 8;
}] subscribeNext:^(NSString * _Nullable x) {
}];
[[self.btnSave rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
@strongify(self);
if([self.viewModel.strNickNameFlag isEqualToString:self.textFieldNickName.text]){
[self.navigationController popViewControllerAnimated:YES];
}else {
[self.viewModel.saveCommand execute:self.textFieldNickName.text];
}
}];
[self.viewModel.saveCommand.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
@strongify(self)
JTSHOW_TIPS(@"昵称修改成功");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
@strongify(self)
[self.navigationController popViewControllerAnimated:YES];
});
}];
[self.viewModel.saveCommand.errors subscribeNext:^(id _Nullable x) {
JTSHOW_TIPS(@"昵称修改失败");
}];
}
感悟
1、vc代码
1、声明了个viewModel并将它实例化
2、在loginEvent 和 bindData方法使vc的view和viewModel建立了绑定和连接的关系
3、loginEvent用来响应ui事件和viewModel网络请求的发起和回调
4、bindData将view和viewModel绑定
4.1、view的改变影响viewModel. self.textFieldNickName.rac_textSignal 影响着self.viewModel,strNickName
4.2、viewModel的改变也影响view. self.viewModel.btnEnableSignal 影响着self.btnSave,enabled, 按钮能不能点击就看 self.viewModel.btnEnableSignal 了.
2、viewModel代码
1、处理btnEnableSignal的业务逻辑,vc的self.btnSave点击取决于它,可以看到只有strNickName的长度大于1才能点击,否则就不能点击,而strNickName的值是通过self.textFieldNickName.rac_textSignal的信号过来的,刚好就应对了上面所说的view的改变影响viewModel ,viewModel的改变也影响view.
2、处理网络请求发起和通过信号回调.