软件层次
工具层(utility,通用的工具,和具体的业务无关)
网络层(负责和server进行交互)
软件层次
工具层(utility,通用的工具,和具体的业务无关)
网络层(负责和server进行交互)
数据持久层(本地缓存、数据库)
model层(原始数据的类载体,比如来自网络或数据库的时间戳,不进行处数据理)
逻辑层(viewmodel层,软件业务功能逻辑相关,可以给每个界面增加个逻辑层,也可以给一个业务功能多个界面增加一个逻辑层)
UI层(显示的view)
控制层(controller是个大杂炖,上面那些层都在这个controller里面彼此交互)
软件框架
大多是MVC模式

缺点:经常会导致C很臃肿,不易管理,所以出现了MVVM。
MVVM模式
MVVM就是将业务逻辑从controller里面抽出来单独生成一个类,降低耦合
如果要想把业务逻辑从controller中抽取出来,以实现逻辑层(viewmodel)是逻辑的载体,那么逻辑层至少需要
1 2
   | 1 实时的接受view里面各种数据源和事件源的变化(比如输入框、按钮等) 2 逻辑任务处理完成后将数据、动作输出至view/controller
   | 
 
要实现这两条,就需要响应式编程的概念。
1
   | 函数响应式编程(Functional Reactive Programing : FRP)  :  面向数据流的变化传播(管道处理,比如过滤,类型映射,订阅,组合,属性绑定)
   | 
 
比如 excel 3-8数码管 订阅(公众号、日报),详见wiki
数据流,逻辑流 这种概念思想很重要,和命令式编程大不一样
由此,Reactive Cocoa 应运而生。
Reactive Cocoa 可以承担以下任务
1 数据流统一封装分发

2 数据(双向)绑定

3 动作事件通知

代码实例
1 2 3 4 5 6 7
   | // data binding RAC(_viewModel,phone) = _phoneTF.rac_textSignal; // 这样可以(只能)观察到textField 源于键盘输入导致的值变化 RAC(_phoneTF,text) = [RACObserve(_viewModel, phone) distinctUntilChanged];
  // 清空_phoneTF _viewModel.phone = @""; // 代码实现 // _phoneTF.text = nil; // 这种方式不行
   | 
 
关于使用RAC(…),有时会有这样的错误error : is already bound to key path "" on object  rac,原因是
1 2 3
   | RAC(self.viewModel,smsCode) = _phoneTF.rac_textSignal; RAC(self.viewModel,smsCode) = _codeTF.rac_textSignal; 给smsCode只能绑定一次,绑给别的信号了,就不能再绑给另外一个信号了,所以绑定慎用,但可以subscribeNext啊
   | 
 
[RACSignal createSignal] 方式创建signal,只创建一次就OK
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
   | -(RACSignal *)validatePhoneSignal {     if (!_validatePhoneSignal) {         _validatePhoneSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {                          if (isValid([[UserBaseInfo share] identityName]) && _idCode.length != 15 && _idCode.length != 18) {                 [subscriber sendError:Error(errCode_toast, @"请输入正确的15或18位身份证号")];                 return nil;             }                          [_service verifyCode:_smsCode idCard:_idCode finish:^(NSError *error) {                                  if (error) {                     [subscriber sendError:error];                 }else{                                          [subscriber sendNext:@(YES)];                     [subscriber sendCompleted];                 }             }];                          return nil;         }];     }          return _validatePhoneSignal; }
   | 
 
[RACSubject subject] 创建的signal,每次都得创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   | -(RACSignal *)rechargeSignal {         RACReplaySubject *subject = [RACReplaySubject subject];     _rechargeSignal = [subject deliverOnMainThread];          [self.submitSignal subscribeNext:^(NSNumber *x) {                  if (x.boolValue) {             [subject sendNext:@(YES)];             [subject sendCompleted];         }else{             [self.querySignal subscribeNext:^(id x) {                 [subject sendNext:@(YES)];                 [subject sendCompleted];             } error:^(NSError *error) {                 [subject sendError:error];             }];         }              } error:^(NSError *error) {         [subject sendError:error];     }];                  return _rechargeSignal; }
   |