iOS開發模式MVVM 2分離業務邏輯

testHs發表於2015-12-13

我想大多初始化定義的程式碼都能看懂,也沒有敘述的必要,我主要把我覺得最主要的幾個部分敘述一下。

代理 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

3.Why Does RACCommand`s block return a signal?

4.MVVM Tutorial with ReactiveCocoa: Part 1/2

相關文章