GICDataBinding是一款基於NSProxy
開發的數據綁定庫,支持數據綁定
和事件綁定
(以爲好的各位,不要吝嗇您的star
)有以下特點功能:javascript
支持JS表達式
前端
@"'姓名:'+$.name.split('').reverse().join('') + ',性別:'+($.isMale?'男':'女')"
複製代碼
- 表達式僅支持單一表達式,若是表達式字符串中出現多個表達式,可能會出現意外。
- 你能夠在單一表達式中調用任意JS中的方法,甚至調用你
預先注入
的方法。這樣一來就爲基於數據綁定開發的功能增長了無限可能。你能夠直接將一些之前在ViewModel
中定義的方法直接注入到JSCore中,使得能夠直接在JS表達中調用這些方法- 你能夠直接在JS表達式中對數據源中的屬性作計算,而後將結果返回。
靈活基於JSCore
開發、注入各類方法
、Class
將會使得開發某些功能變得異常的簡單。甚至若是你的部分UI是基於Texture
這樣的支持自動佈局的庫開發的話,那麼對於構建UI這樣的任務變得異常的簡單。vue
單向綁定java
雙向綁定git
雙向綁定在本質上仍是基於單向綁定的,可是GICDataBinding對某些UI組件進行了封裝,使得能夠直接一行代碼就能完成雙向綁定。相似於前端
vue
中的model
github
支持對NSMutableArray
進行觀察。objective-c
當數組內容變動後,你能夠獲得相應的回調。這樣一來你能夠開發出類前端
VUE
那樣的自動根據數組內容變動,從而update UI的功能。express
支持事件綁定
。重點數組
當前對於
UIControl
已經實現了相關的事件綁定。其餘的事件開發者能夠本身去實現。實現的方法也是很簡單的安全這裏面的技術基礎就是,基於NSProxy實現對方法調用的攔截,從而能夠實現相似方法交換的目的。也就是說這裏能夠不經過方法交換技術就能實現相似的功能需求。PS:有興趣能夠看下這部分源碼,我相信必定會讓你有所收穫。
固然也支持Swift
開發。可是要求Swift
中的數據類必須是NSObject
子類。
pod 'GICDataBinding'
複製代碼
github地址:github.com/ghwghw4/GIC…
全部的數據綁定功能的前提是一個能夠被觀察
的對象,就像KVO
那樣的。可是GICDataBinding
不是基於KVO
開發的,而是基於NSProxy
開發的,所以在進行數據綁定之前,須要對你的數據源作一個轉換,將數據源變成可觀察對象,這一切的原理基礎是基於NSProxy
實現的。
首先你要有一個數據類,好比UserInfo
這樣的數據模型
數據類必須實現GICObserverProtocol
協議,這個協議實際上是一個空協議,僅僅是用來標記該類是可觀察的。因爲GICDataBinding
是支持嵌套的,所以全部數據模型中的對象想要能夠被觀察,那麼都須要實現GICObserverProtocol
協議。
@interface TestData : NSObject<GICObserverProtocol>
@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)NSInteger age;
@property(nonatomic,assign)BOOL isMale;
@property(nonatomic,strong)UserAddress *address;
@property (nonatomic,strong)NSDictionary *dict;
@property (nonatomic,strong)NSMutableDictionary *dict2;
@property (nonatomic,strong)NSArray *array;
@property (nonatomic,strong)NSMutableArray *mutArray;
@property(nonatomic,assign)NSInteger timeTick;
+(instancetype)testData;
@end
複製代碼
對數據模型調用gic_observer
方法,你會得到一個能夠被觀察的數據模型。
TestData *data = [[TestData testData] gic_observer];
複製代碼
JS表達式中的
$
表示數據源自己,所以若是你想要訪問數據源的某個屬性或方法,那麼必須使用$
來訪問
普通的單向綁定。
[btn gic_addBinding:createDataBinding(theme, @"$.backgroundColor", ^(UIButton *target, id newValue) {
[target setTitleColor:newValue forState:UIControlStateNormal];
})];
複製代碼
這樣當數據源中的backgroundColor
屬性改變的時候就會觸發回調
直接將表達式綁定到目標對象的屬性上。
[lbl gic_addBinding:createPropertyDataBinding(user, @"'計數:'+$.timeTick", @"text")];
複製代碼
經過createPropertyDataBinding
能夠建立一個屬性綁定,將表達式'計數:'+$.timeTick
的結果自動綁定到UILable
的 text
屬性。
注意:createPropertyDataBinding 在內部實現的時候基於
setValue:forKey
來實現的,所以確保這個屬性是支持KVC的。若是這個屬性不支持,那麼使用第一種方法也能達到數據綁定目的。
雙向綁定。
UISwitch *sw = [[UISwitch alloc] initWithFrame:CGRectMake(10, CGRectGetMaxY(btn.frame)+10, 100, 44)];
[sw gic_towwayBinding:user propertyName:@"isMale"];
[self.view addSubview:sw];
複製代碼
你能夠經過
gic_towwayBinding
來建立一個雙向綁定。propertyName
表示的是數據源中的屬性名稱。也就說,當數據源中的isMale
改變的時候,UISwitch
的isOn
也會跟着改變。而當UISwitch
的isOn
被改變的時候,數據源中的isMale
屬性也會跟着改變。但這裏你不用擔憂會陷入死循環,類庫已經作了比較處理,若是兩次變動的value是同樣的,那麼不會重複觸發。
對NSMutableArray
進行觀察。
第一步固然是須要將array轉換成可觀察對象了。經過調用gic_observer
來實現。。
arrayObserve.changedBlock = ^(NSMutableArray *mutArray, GICMutableArrayChangedType changedType, NSArray *params) {
switch (changedType) {
case GICMutableArrayChangedAddObject:
NSLog(@"GICMutableArrayChangedAddObject:%@",params[0]);
break;
case GICMutableArrayChangedRemoveObject:
NSLog(@"GICMutableArrayChangedRemoveObject:%@",params[0]);
break;
case GICMutableArrayChangedRemoveAllObjects:
NSLog(@"GICMutableArrayChangedRemoveAllObjects");
break;
case GICMutableArrayChangedRemoveLastObject:
NSLog(@"GICMutableArrayChangedRemoveLastObject:%@",params[0]);
break;
case GICMutableArrayChangedSortArray:
NSLog(@"GICMutableArrayChangedSortArray:%@",mutArray);
break;
case GICMutableArrayChangedInsertObject:
NSLog(@"GICMutableArrayChangedInsertObject:%@,index:%@",params[0],params[1]);
break;
case GICMutableArrayChangedReplaceObject:
NSLog(@"GICMutableArrayChangedReplaceObject:%@,index:%@",params[0],params[1]);
break;
default:
break;
}
};
複製代碼
目前GICDataBinding
支持的課觀察方法的枚舉都已經在上面列出。
在表達式中調用注入的JS方法。
[GICJSContextManager manager].jsContext[@"customFunc"] = ^(JSValue*value){
//這裏以將Color 轉換成字符串爲例
UIColor *color = [value toObject];
CGFloat r,g,b,a;
[color getRed:&r green:&g blue:&b alpha:&a];
return [NSString stringWithFormat:@"r:%f,g:%f,b:%f",r,g,b];
};
// 數據綁定表達式直接調用js方法
[lbl gic_addBinding:createPropertyDataBinding(theme, @"'顏色轉換:'+customFunc($.titleColor)", @"text")];
複製代碼
注入JS方法有兩種方式
直接以下上面的方法,採用block方式注入
調用 [[GICExpresionCalculator calculator].jsContext evaluateScript:jsString] 注入JS腳本
GICDataBinding
中的事件綁定只能調用JS代碼,可是得益於JSCore可以直接調用本地代碼,也就意味着你也能夠直接在事件綁定中調用本地代碼。
在作事件綁定前,首先你要有一個ViewModel
。一樣,這個ViewModel
須要實現GICObserverProtocol
協議。好比下面:
@interface TestViewModel : NSObject<GICObserverProtocol>
@property (nonatomic,copy)NSString *v1;
@property (nonatomic,assign)NSInteger v2;
/// 全部能夠被JS調用的方法,都必須帶有一個參數,不然沒法調用
-(void)onButtonClicked:(id)param;
@end
複製代碼
初始化ViewModel
testViewModel = [[[TestViewModel alloc] init] gic_observer];
複製代碼
綁定按鈕的點擊事件。
[btn gic_addEventBinding:[GICEventBinding bindingWidthDataSource:testViewModel expression:@"$.onButtonClicked(`${$.v1}----${$.v2}`)"] forControlEvents:UIControlEventTouchUpInside];
複製代碼
從這裏你能夠看到,當按鈕點擊事件觸發後,就會執行JS腳本
$.onButtonClicked(`${$.v1}----${$.v2}`)
複製代碼
從這裏看到,是調用的
testViewModel
中的onButtonClicked
方法,而且傳入字符串參數。
綁定事件中直接設置數據源的value
[btn gic_addEventBinding:[GICEventBinding bindingWidthDataSource:testViewModel expression:@"$.v2++"] forControlEvents:UIControlEventTouchDown];
複製代碼
這裏每當點擊事件觸發後,就會對數據源的
v2
屬性+1
。若是有其餘地方綁定了v2
屬性,那麼也會同時更新數據綁定
事件綁定直接調用本地代碼。
[btn gic_addEventWatch:^(NSArray * _Nullable params) {
NSLog(@"點擊了");
} forControlEvents:UIControlEventTouchUpInside];
複製代碼
這裏其實已經不算事件綁定了,能夠說是事件代理。
GICDataBinding
基於NSProxy
實現了一套能夠直接block
回調按鈕事件的庫。如今你無需RAC
就能實現一樣的通能。事實上,你能夠對任意對象的任意方法進行watch
,在某些狀況下,你壓根就無需方法交換
就能實現相似方法交換的功能,並且這種基於NSProxy
實現調用攔截的過程是安全、不衝突的,不會出現方法交換
可能引發的crash問題(屢次交換)。
注意:
全部能夠在事件綁定中被調用的
ViewModel
中定義的方法,必須帶有一個參數,哪怕這個參數你不會用到,並且目前只支持帶有一個參數的方法。若是你須要傳入多個參數,目前惟一的方法是以數組的方式傳入
說明
不論是數據綁定
仍是事件綁定
,由於都是基於JS表達式來實現的,所以想要熟練的將數據綁定應用到項目中,還須要您對JavaScript
有必定的瞭解,另外GICDataBinding
的JS引擎是基於JavaScriptCore
來實現的,所以若是你想在項目中擴展JSCore甚至想要之前端開發同樣,直接在JS中建立ViewModel,那麼須要你對JavaScriptCore
有必定的瞭解
基於GICDataBinding
數據綁定系統,你能夠作一些不少之前實現起來比較複雜的功能。好比:
app 主題(Example 有例子)
能夠直接基於綁定系統,將一些主題元素綁定到提供主題數據的模型。這樣當用戶修改主題的時候,app能夠作出實時的改變。
從新思考ViewModel
的定義。將ViewModel
JS化
你如今能夠把部分或者整個原來已有的ViewModel移入JSCore,而後經過數據綁定系統直接調用
配合Texture
實現整個UI 基於綁定系統的可響應式設計。
HotFix
因爲數據綁定和事件綁定都是採用JS表達式的方式調用,所以理論是上能夠直接經過下發JS腳原本動態修復、增長功能的。固然,這僅僅是理論上,真要實現起來仍是有很大開發量的