前言: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