我想大多初始化定義的程式碼都能看懂,也沒有敘述的必要,我主要把我覺得最主要的幾個部分敘述一下。
代理 Protocol
為什麼先說代理。這也是之前和慎哥也說過cell裡面有點選事件怎麼寫。(不知道這麼寫對不對…後面看一部分原始碼之後會再聊這個話題,先留坑)代理可以幹什麼,跨Controller傳值。跨Controller調方法。
我們之前寫代理,都是在某個Controller裡的.h檔案最上面建立代理。但實際上,Xcode提供了專門的Protocol檔案。之前沒有搞明白也是因為我覺得代理必須要再某個檔案裡宣告。
所以,當我們單獨宣告瞭一個Protocol檔案的時候,就意味著,這個Protocol可以像一個類一樣來宣告變數了。
RACCommand
這個東西是做啥的。我只能說我解釋不好,因為我沒有完全理解這個東西。我只能把我理解的說出來。
我們的按鈕都有一個點選事件。當點選的時候出發一個函式。
但是,當我們用了RACCommand的時候,我們的點選事件就可以這麼寫了。
self.pushBtn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"test signal");
return [RACSignal empty];
}];
和我之前寫過的這種寫法又不一樣了。這種寫法其實是對button addtarget那個方法的一個rac式的封裝。
[[self.testBtn rac_signalForControlEvents:UIControlEventTouchUpInside]
subscribeNext:^(id x) {
TestViewController *testVC = [[TestViewController alloc] init];
[self.navigationController pushViewController:testVC animated:YES];
}];
用第一種方法的原因呢,我們可以把點選事件賦值成為一個RACCommand型別的屬性。既然可以變成一個屬性了,那麼就可以重新定義並且賦值。
分離點選事件
我們新建一個FirstViewModel,在FirstViewModel.h中增加一個
@property (strong, nonatomic) RACCommand *excutePush;
然後我們讓剛剛在FirstViewController裡定義的那個pushBtn的rac_command,將它賦值為FirstViewModel裡的excutePush
self.pushBtn.rac_command = self.viewModel.excutePush;
這麼一賦值,就達成了一個目的。按鈕的事件在viewModel中執行。
需要注意的是,RACCommand的block返回的時一個signal。所以,在viewModel中,我們要這麼寫
self.excutePush = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"test signal");
return [RACSignal empty];
}];
這樣,我們就實現了對點選事件的分離。
分離跳轉
分離跳轉,就要用到我開始說的代理了。
我們做一個MVVMdemoService的代理,我放在Protocol資料夾裡了。這個代理就宣告瞭一個方法
- (void)pushViewModel:(id)viewModel;
我們在NSLog(@”test signal”);下面增加
[self.service pushViewModel:viewModel];
我們還要實現這個代理。
在ray中的教程和雷大神的MVVMReactiveCocoa都是新建了一個Impl檔案,專門用來跳轉,基本思路就是navigation本身就是一個堆疊,其實所有的vc都是在navigation其中的。我們只要控制這個這個最基本的navigation的跳轉就可以了。
我們新建一個MVVMdemoImpl檔案,裡面有一個初始化的方法。
- (instancetype)initWithNavigationController:(UINavigationController *)navigationController
我們把根navigation傳進去來進行邏輯跳轉。
我們在初始化的時候加上這兩句核心程式碼。
self.demoImpl = [[MVVMdemoImpl alloc] initWithNavigationController:self.naviVC];
self.firstViewModel = [[FirstViewModel alloc] initWithService:self.demoImpl];
第一句話是宣告瞭一個demoImpl,將navigation穿進去。
第二句話是宣告瞭一個firstViewModel,把第一個demoImpl傳了進去。這個地方的疑問在於,我們宣告的時候是
-(instancetype)initWithService:(id<MVVMdemoService>)service
引數是一個代理。我們傳的時一個NSObject型別的值。而且在MVVMdemoImpl.m中,也沒有對於代理的賦值為自己。
我是這麼理解的,如果有不對,還請諒解。
當我們加入代理MVVMdemoService在MVVMdemoImpl的時候,因為MVVMdemoImpl是一個nsobject型別,而MVVMdemoService也是一個nsobject型別。所以,此時我們的MVVMdemoImpl具有MVVMdemoService的屬性了,我們做的就是,讓FirstViewModel裡的service的代理即是MVVMdemoImpl。
簡單的說。
就是MVVMdemoImpl == FirstViewModel.service
那麼這樣的話,我們的service就可以執行MVVMdemoImpl裡的pushViewModel方法了。
小結
其實上面的最後AppDelegate的賦值代理這一塊還不是很明白。有時間再說說吧。好久沒寫部落格就想發一篇了。
以上完整程式碼在MVVMdemo
參考連結
1.leichunfeng/MVVMReactiveCocoa
2.ReactiveCocoa Essentials: Understanding and Using RACCommand