前言:2年前空闲时间玩了Vue.js, 发现利用数据双向绑定,开发如此轻松简洁,我了解iOS也有相似的框架 ReactiveCocoa, ReactiveCocoa有点复杂和笨重,我只须要简单点的数据绑定,因此写了一个轻量级的数据绑定,麻烦你们看一下,有问题请指点下git
- 通常配合MVVM架构使用,主要用于View和ViewModel双向绑定,也可用于其余数据双向绑定
- 这里介绍下双向数据绑定好处:
- View.textField 跟 ViewModel.text 绑定,用户在输入框textField输入"Hello World",text也会响应式更新,此时text = @"Hello World", 咱们只要对text进行处理
- 若是咱们从网络获取Model,Model 转换并赋值于 ViewModel.text,View也会响应式更新界面, 整个过程都是对ViewModel.text进行操做,不会再去处理View部分
github地址: github.com/shidavid/DV…
其余例子:利用 DVDataBind 双向绑定 + MVVM 简单实现登陆界面github
// 这里只是展现响应式变化
DVDataBind
._inout(self.demoModel, @"text")
._inout_ui(self.demoView.textField, @"text", UIControlEventEditingChanged)
._out(self.demoView.label, @"text")
// 点击button
- (void)onClickForButton:(UIButton *)sender {
self.demoModel.text = @"Hello World";
}
复制代码
- 不限定只能 View 与 ViewModel 绑定,只要支持KVC的数据都能双向绑定
- 使用链式编程,支持多项绑定
- 支持单向数据流/双向数据流
- 支持 字符串,整形,浮点型,布尔类型 之间数据自动转换 (对象类型除外)
- 支持过滤, 限制,转换, 观察数组某一位数据变化
- 无需继承基类,无需手动解绑, 当目标对象内存释放,DataBind自动解绑和释放内存
A 与 B 双向数据绑定,Ain数据变化更新Aout、Bout数据,Bin同理 编程
有时候 A 与 B 双向绑定,B 与 C 双向绑定, 其实至关于 A、B、C 一块儿绑定在一条数据链Chain上, 每当有一个in数据变化, 发送新数据到Chain上,再由Chain更新全部的out数据 数组
这样实现单向/双向数据流 bash
/*
object为目标对象, property是object拥有的属性
object不能为nil,property可为nil
*/
._inout(object, @"property")
举例:
/*
objectA -> a1, a2
objectB -> b
objectC -> c
a一、a二、b、c 正常状况为同一类型, 若是不一样类型查看下面 "3.转换"
*/
DVDataBind
._in(objectA, @"a1")
._inout(objectA, @"a2")
._inout(objectB, @"b")
._out(objectC, @"c");
复制代码
/*
UI: 支持 UIControlEvents
property: 经过触发 UIControlEvents 会产生数据变化的 属性
*/
._inout_ui(UI, @"property", UIControlEvents)
举例:
/*
view -> UITextField *textField;
viewModel -> NSString *text;
*/
DVDataBind
._inout_ui(view.textField, @"text", UIControlEventEditingChanged)
._inout(viewModel, "text");
/*
view -> UILabel *label;
viewModel -> NSString *text;
UILabel 不支持 UIControlEvents
*/
DVDataBind
._in(viewModel, "text");
._out(view.label, @"text");
/*
view -> UISwitch * switch;
viewModel -> BOOL isON;
*/
DVDataBind
._inout_ui(view.switch, @"on", UIControlEventValueChanged)
._inout(viewModel, "isON");
/*
view -> UIImageView *imageView;
viewModel -> UIImage *image;
UIImageView 不支持 UIControlEvents
*/
DVDataBind
._in(viewModel, "image");
._out(view.imageView, @"image");
/*
view -> UISlider *slider;
viewModel -> float value;
*/
DVDataBind
._inout_ui(view.slider, @"value", UIControlEventValueChanged)
._inout(viewModel, "value");
/*
view -> UIProgressView *progressView;
viewModel -> float value;
*/
DVDataBind
._inout_ui(view.progressView, @"progress", UIControlEventValueChanged)
._inout(viewModel, "value");
/*
view -> UISegmentedControl *segmented;
viewModel -> int index;
*/
DVDataBind
._inout_ui(view.segmented, @"selectedSegmentIndex", UIControlEventValueChanged)
._inout(viewModel, "index");
/*
view -> UIStepper *stepper;
viewModel -> int index;
*/
DVDataBind
._inout_ui(view.stepper, @"value", UIControlEventValueChanged)
._inout(viewModel, "index");
/*
view -> UIButton *button;
点击Button改变的是highlighted值,highlighted容易打错, 仍是建议用 addTarget
*/
DVDataBind
._in_ui(view.button, @"highlighted", UIControlEventTouchUpInside)
._out_key_any(@"自定义", ^{
// 点击触发
});
复制代码
/*
普通对象转换
ClassA objectA -> a;
ClassB objectB -> b;
*/
DVDataBind
._inout_cv(objectA, @"a", ^ClassA *(ClassB *变量) {
// 处理程序
return 转换为ClassA的数据更新 objectA.a;
})
._inout_cv(objectB, @"b", ^ClassB *(ClassA *变量) {
// 处理程序
return 转换为ClassB的数据更新 objectB.b;
} );
特殊状况:
/*
view -> UITextField *textField;
viewModel -> NSString *text;
viewModel -> int number;
支持 字符串,整形,浮点型,布尔类型 之间数据自动转换 (对象类型除外)
若是text为非数字, 则number为0
*/
DVDataBind
._inout_ui(view.textField, @"text", UIControlEventEditingChanged)
._inout(viewModel, "text")
._inout(viewModel, "number");
/*
view -> UITextField *textField;
view -> UILabel *label;
viewModel -> NSString *text;
viewModel -> int number;
这里 更新值有 NSString, int 类型,上面说过这些类型之间自动转换
viewModel->text 获取更新值自动转为NSString, 处理完返回NSString 再去更新本身
viewModel->number 获取更新值自动转为NSNumber, 处理完返回NSNumber 再去更新本身
*/
DVDataBind
._inout_ui(view.textField, @"text", UIControlEventEditingChanged)
._out_cv(view.label, @"text", ^NSString *(NSString *text) {
NSString *tempText = [NSString stringWithFormat:@"AAA - %@ - BBB",text];
return tempText;
})
._inout_cv(viewModel, @"text", ^NSString *(NSString *text) {
NSString *tempText = [NSString stringWithFormat:@"CCC - %@ - DDD",text];
return tempText;
} )
._inout_cv(viewModel, @"number", ^NSNumber *(NSNumber *num) {
int value = [num intValue];
return @(value + 123456);
});
复制代码
/*
objectA -> array
array必须为NSMutableArray类型, 绑定前必须初始化, 数组可提早赋值, 也能够为空
*/
._inout_arr(objectA, @"array", 1)
// 更新数组某位必须该方法
NSMutableArray *pArray = [objectA mutableArrayValueForKey:@"array"];
pArray[0] = @(123456);
pArray[1] = @"Hellow World"; //这里更改了第1位数据, 响应
pArray[2] = object;
复制代码
// property类型为BOOL类型
._out_not(objectA, @"property");
举例:
/*
view -> UITextField *textField;
view -> UISwitch * switch;
view -> UISwitch * switchNot;
当textField.text长度不为0, 则switch.on = YES, switchNot.on = NO
当 switch.on = NO, switchNot.on = YES
*/
DVDataBind
._in_ui(view.textField, @"text", UIControlEventEditingChanged)
._inout_ui(view.switch, @"on", UIControlEventValueChanged)
._out_not(view.switchNot, @"on")
复制代码
// 自定义名不能同样, 类型为更新数据类型 (类型、变量可不写)
._out_key_any(@"自定义名1", ^(Class 变量){
// 处理代码1
})
._out_key_any(@"自定义名2", ^(Class 变量){
// 处理代码2
})
._out_key_any(@"自定义名3", ^{
// 处理代码3
});
举例:
// 整形、浮点型、布尔类型,必须是NSNumber 类型
._out_key_any(@"自定义名", ^(NSNumber *num){
// 处理代码
});
//更新值只是NSString类型
._out_key_any(@"自定义名", ^(NSString *text){
// 处理代码
});
// 若是更新数据类型多样,就用id
._out_key_any(@"自定义名", ^(id value){
//判断value为哪一个Class, 进行处理
});
复制代码
._filter(^BOOL(Class 变量) {
// 这里能够对数据进行判断,限制,校验等等
return YES/NO; // 返回YES 则正常数据更新, NO不更新
})
举例:
//更新值只是NSString类型
._filter(^BOOL(NSString *text) {
return text.length <= 20; //限制字符串长度为20
})
//更新值为整形、浮点型、布尔类型,必须是NSNumber类型
._filter(^BOOL(NSNumber *num) {
return [num intValue] <= 100; //限制数字最大为100
})
//若是更新值为多类型,例若有NSString,NSNumber, 则写id
._filter(^BOOL(id value) {
//判断value为哪一个Class, 进行处理
return YES/NO;
})
复制代码
// 一开始绑定生成一条数据链
DVDataBind
._inout(objectA, @"a")
._inout(objectB, @"b")
// 将objectBB.bb 加入 objectA.a 的数据链中,
// objectA.a、objectB.b、objectBB.bb在同一数据链上
DVDataBind
._inout(objectA, @"a")
._inout(objectBB, @"bb")
// 至关于
DVDataBind
._inout(objectA, @"a")
._inout(objectB, @"b")
._inout(objectBB, @"bb")
复制代码
// 解绑objectA的全部 property
[DVDataBind unbindWithTarget:objectA];
// 解绑objectA的 a
[DVDataBind unbindWithTarget:objectA property:@"a"];
// 解绑objectA的 控件a
[DVDataBind unbindWithTarget:objectA property:@"a" controlEvent:UIControlEventValueChanged];
// 解绑objectA的 数组a 的某位
[DVDataBind unbindWithTarget:objectA property:@"a" index:1];
// 解绑objectA的 a 所在数据链的 输出Block "XXX"
[DVDataBind unbindWithTarget: objectA property:@"a" outBlockKey:@"XXX"];
复制代码
编译DVDataBindKitShell 网络
生成Framework拖入项目 架构
项目 Target -> Build Settings -> Linking ->Other Linker Flags 添加参数: -all_load -ObjC 框架
在PCH文件导入ide
#import <DVDataBindKit/DVDataBindKit.h>
复制代码
github地址: github.com/shidavid/DV…
谢谢你们观看,有兴趣麻烦点个星星关注下 😁😁😁post