The fastest way to get started with ReactiveCocoa

Preface

Due to the lack of time, not only update so much, the follow-up will continue to update the “most advanced” let you get started ReactiveCocoa, at present only a brief introduction to the methods RAC core, also need to follow with the actual development of MVVM+ReactiveCocoa. If
love my article, I can focus on, micro-blog: Yuan Zheng Seemygo, welcomed the exchange of. Can also come to a small brother, understand our iOS training courses. And then update

1.ReactiveCocoa common operating methods are introduced.

  • For 1.1 ReactiveCocoa operation all signal (RACSignal) can operate, because all operating methods are defined in the RACStream.h, so long as the successor to the RACStream had the operation method.
  • 1.2 ReactiveCocoa operation thinking is the use of Hook (hook) thought, Hook is used to change the API (application programming interface: Method) the results of the implementation of the technology. Hook useful: intercepted API call technology. Hook principle: every time you call a API to return the results, first of all, do your own way to change the output of the results.
  • Methods 1.3 ReactiveCocoa bind core core ReactiveCocoa operation is bind (binding), and the core of development, RAC is bound before the development is the assignment, and RAC development, should focus on binding, is when an object is created, it is bound after the things you want to do but, after not to do things in the assignment. Columns such as: to show the data to the control, before the override control setModel method, with RAC can be created at the beginning of the control, it is bound to a good data. Rarely use the bind method in the development of bind, belongs to the bottom of the method in RAC RAC package has been a lot of good with other methods, the bottom is called bind, usage is simpler than bind. Bind method is simple introduction and use.
Suppose / / want to monitor the contents of the text box, and every time the output, output in the contents of the text box stitching a paragraph of text "/ / one way: in the return after stitching. [_textField.rac_textSignal subscribeNext:^ (ID x) {NSLog (@ "% @ x, output:"); / /}]; two: splicing in return before the results, using the bind method in RAC processing. / / bind method parameters: the need to pass a return value is block / / RACStreamBindBlock parameter RACStreamBindBlock is a type of block, the return value is the signal parameters (value, stop), so the return value of the block parameter is a block. / / RACStreamBindBlock: / / parameter (value): received the original value signal, do not handle / / parameter two (*stop): used to control the binding of Block, if *stop = yes, that will be the end of binding. / / return value: signal, good processing, in return out of this signal by general RACReturnSignal, the need to manually import header file RACReturnSignal.h. Use the bind method: / / / / step 1 to a return value of RACStreamBindBlock block. 2 / the description of a RACStreamBindBlock type bindBlock as the return value of block. 3 / describe a return signal, as the return value of bindBlock. Note: / / do signal results in bindBlock. The underlying implementation: / / 1 / / source signal called bind, will re create a binding signal. 2 / when bound signal is a subscription, will invoke the binding in didSubscribe signals, generate a bindingBlock. 3 / / when the source signals have content will be issued, the content is delivered to bindingBlock, call bindingBlock (value, stop) / / 4 call bindingBlock (value, stop), will return a complete signal processing (RACReturnSignal). 5 / subscribe to RACReturnSignal, will get the binding signal sent out to subscribers, the content of signal processing is complete. / / Note: different subscribers, save different nextBlock, see the source code, must see clearly what is the subscriber. #import < / / manual import here need to use RACReturnSignal; ReactiveCocoa/RACReturnSignal.h>. [[_textField.rac_textSignal bind:^RACStreamBindBlock{: / / block / / what they call: indicates that the binding a signal. Return ^RACStream (ID value, BOOL * *stop) {/ / what I call block: when the signal is issued a new value, will come to this block. Block: / / treatment / / return value to return, out through the return [RACReturnSignal return:[NSString stringWithFormat:@ "signal. Output:% @, value]];};}] subscribeNext:^ (ID x) {NSLog ("% @ @ ", x);}];
  • 1.4ReactiveCocoa mapping method (flattenMap, Map) flattenMap, Map is used to map the contents of the source signal into a new content.

FlattenMap simple use

/ / monitor the contents of the text box to change the structure, re mapped to a new value. / / flattenMap function: source signal content is mapped into a new signal, the signal can be of any type. Step flattenMap: / / 1 / / pass a block, block type is the return value of the RACStream parameter, value / / 2 parameter value is the source signal, get the source signal processing content / / 3 packaged into a RACReturnSignal signal, back out. The underlying implementation: / / 0.flattenMap / / flattenMap internal call bind method, the return value of flattenMap block, will return the value of bindBlock in bind. 1 / when the subscription binding signal will generate bindBlock. 2 / when the source sends a signal, it will call the bindBlock (value, *stop) / / the 3 call to bindBlock, will call the flattenMap block, block flattenMap: the signal data package deal. 4 / signal will eventually return as the return signal in bindBlock, as the signal back to bindBlock. 5 / / return signal to subscribe to the bindBlock, it will get the binding signal sent out to subscribers, the content of signal processing is complete. [[_textField.rac_textSignal flattenMap:^RACStream * (ID value) {/ / block what time: when the source signal is issued, will call this block. Block: / / change the source signal content. / / return value: binding signal return [RACReturnSignal return:[NSString stringWithFormat:@ ". Output: value]];}]% @", subscribeNext:^ (ID x) {/ / subscribe binding signal, whenever the source signal transmitting content, after processing, will call this block. NSLog (@ "% @", x);}];

Map simple use:

/ / monitor the contents of the text box to change the structure, re mapped to a new value. / / Map function: the value of the signal source is mapped into a new value using the Map: / / / / step 1 to a block type is the returned object parameter is value / / 2.value is the source signal directly to the content the content of the source signal processing to deal with / / the 3 content, direct return is good, without packing into the signal. The return value is the value of the map. The underlying implementation: / / 0.Map / / Map bottom is called flatternMap, the Map value returned in block as flatternMap value in block. 1 / when the subscription binding signal will generate bindBlock. 3 / when the source sends a signal, it will call the bindBlock (value, *stop) / / the 4 call to bindBlock, will call the flattenMap block / / 5.flattenMap internal block will call the Map in the block, the content of packaged returned signals in the Map returned by block. 5 / signal will eventually return as the return signal in bindBlock, as the signal back to bindBlock. 6 / / return signal to subscribe to the bindBlock, it will get the binding signal sent out to subscribers, the content of signal processing is complete. [[_textField.rac_textSignal map:^id (ID value) {/ / when the source signal is issued, will call the block, modify the source signal content / / return value: the source signal is processed in content. Return [NSString stringWithFormat:@ "output: value];}]% @", subscribeNext:^ (ID x) {NSLog ("% @ @", x);}];
  • The difference between FlatternMap and 1.FlatternMap in the Block return signal to Map. Block returns object in 2.Map. 3 development, if the signal is not the value of the signal, the mapping is generally used in the development of Map 4, if the signal is sent to the value of the signal, the mapping generally use FlatternMap.
  • Summary: signalOfsignals with FlatternMap.
/ / create signal in the signal RACSubject *signalOfsignals = [RACSubject subject]; RACSubject *signal = [RACSubject subject]; [[signalOfsignals flattenMap:^RACStream * (ID value) {/ / when signalOfsignals signals signals will call the return value;}] subscribeNext:^ (ID x) {/ / signalOfsignals only signal signals will call, because the internal subscription signal returned in the bindBlock also, is the signal returned by flattenMap. The signal is returned by flattenMap / / A, will call. NSLog (@ "%@aaa", x); / /}]; signal transmission signal [signalOfsignals sendNext:signal] signal [signal sendNext:@1]; / / content;
  • 1.5 combination of ReactiveCocoa operating methods. Concat: splicing signal in a certain order, when a number of signals, the order of the received signal.
RACSignal *signalA = [RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@1]; [subscriber sendCompleted]; return nil;}]; RACSignal *signalB = [RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@2]; return nil;}]; / / signalA splicing to signalB, signalA sent, signalB is active. RACSignal *concatSignal = [signalA concat:signalB]; / / will only need to face the development of splicing signal. / / signal splicing does not require a separate subscription, subscription signalA, signalB will automatically subscribe to / / internal. / / Note: the first signal must be sent, the second signals are activated [concatSignal subscribeNext:^ (ID x) {NSLog ("% @ @", x);}]; / / concat / / 1: when the underlying implementation of splicing signal is subscription, will call the didSubscribe / 2.didSubscribe splicing signal, will first subscribe to the first source signal (signalA) / / the 3 will perform the first signal source (signalA) didSubscribe / / 4 first source signal (signalA) transmitted in didSubscribe, will call the first signal source (signalA) by nextBlock subscribers, subscriber value splicing signal sent out. 5 / / the first source signal (signalA didSubscribe) send completed, will call the first signal source (signalA) completedBlock subscribers, subscribe to second source signals (signa LB) activated only at this time (signalB). 6 / second subscription source signal (signalB), the implementation of the second source signals (signalB) of didSubscribe / / 7 second source signal (signalA) transmitted in didSubscribe value, the value will be sent out by splicing signal subscribers.
  • Then: is used to connect the two signals, and when the first signal is completed, the then will return the signal. / / then: for connecting two signal when the first signal, signal / connections will be returned by then note the use of the then, before the value of the signal will be ignored. / / the underlying implementation: 1, to filter the signal before the fall of a value. 2 use concat to connect then return signal [[[RACSignal createSignal:^RACDisposable * (id< RACSubscriber> subscriber) {[subscriber sendNext:@1]; [subscriber sendCompleted]; return nil; then:^RACSignal return [RACSignal createSignal:^ RACDisposable}] *{* (id< RACSubscriber> subscriber) {[subscriber sendNext:@2]; return nil;}]}]; subscribeNext:^ (ID x) {/ / only received second a signal value is then, the return signal value of NSLog (@ “% @”, x); merge:}]; a plurality of signals into one signal, a signal when a new value is called
/ / merge: multiple signal into a signal to create multiple signal RACSignal / / *signalA = [RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@1]; return nil;}]; RACSignal *signalB = [RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@2]; return nil;}]; / / with signal. Any one signal to send data, can listen to. RACSignal *mergeSignal = [signalA merge:signalB]; [mergeSignal subscribeNext:^ (ID x) {NSLog ("% @ @", x);}]; / / implementation: / / 1 combined signal is subscription when it will traverse all of the signals and send these signals. 2 / each send a signal, the signal will be subscribed is / / the 3 combined signal is a subscription, will subscribe to all the signal. 4 / as long as there is a signal is emitted will be monitored.
  • ZipWith: compresses the two signals into a single signal, only when the two signals simultaneously send the signal content, and the contents of the two signals are merged into a tuple, will trigger the compressed flow of next events.
RACSignal *signalA = [RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@1]; return nil;}]; RACSignal *signalB = [RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@2]; return nil;}]; / / compression signal A signal B RACSignal *zipSignal = [signalA zipWith:signalB]; [zipSignal subscribeNext:^ (ID x) {NSLog (@ "% @", x);}]; / / implementation: / / 1 defines the compressed signal, will automatically subscribe to signalA, signalA or signalB signalB / / 2 whenever the signal will determine signalA, signalB has not issued a signal, the signal will be issued recently are packed into tuple hair A.
  • CombineLatest: will combine multiple signals, and get the latest values of each signal, must be at least once a merger of each sendNext signal, will trigger the merger signal. RACSignal *signalA = [RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@1]; return nil;}]; RACSignal *signalB = [RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@2]; return nil;}]; / / the two signal into a signal, like zip, not what is the difference between RACSignal *combineSignal = [signalA combineLatestWith:signalB]; [combineSignal subscribeNext:^ (ID x) {NSLog (“% @ @”, x);}]; / / implementation: / / the 1 when the combined signal is the internal subscription, will automatically subscribe to signalA, signalB, must be two signals are issued, will be triggered. 2 / / and the two signal into yuan Group issued. Reduce polymerization: used for signal generated content is the signal tuple tuple of values aggregated into a value of RACSignal *signalA = [RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@1]; return nil;}]; RACSignal *signalB = [RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@2]; return nil;}]; / / / / common usage of polymerization, (first polymerization). CombineLatest: (id< NSFastEnumeration> signals (ID) reduce: (block) ^ (reduceBlock)) / / reduce: / / reduceblcok parameters, the number of signal combinations, reduceblcok has many parameters, each parameter is before the signal sent by the content / the return value of reduceblcok signal after the content of polymerization. RACSignal *reduceSignal = [RACSignal combineLatest:@[signalA, signalB] reduce:^id (NSNumber *num1, NSNumber *num2) {return [NSString, num1 stringWithFormat:@ “% @% @”, num2];}]; [reduceSignal subscribeNext:^ (ID x) {NSLog (“% @ @”, x);}]; / / implementation: / / 1 subscription aggregation signal, each content issued will be the implementation of reduceblcok, the signal is converted into reduceblcok content value. 1.6 filtering of ReactiveCocoa operations. Filter: filtering signal, it can be used to obtain the signal to meet the conditions of the filter. / /: / / each time signal, will filter out the judgment condition. [_textField.rac_textSignal filter:^BOOL (NSString *value) {return value.length > 3;}]; ignore: ignores some value. After the signal / calling filter filter, ignore the value of ignore [[_textField.rac_textSignal ignore:@ “1” subscribeNext:^ (ID x) {NSLog (“% @ @”, x); distinctUntilChanged:}]; when the last value and the current value will change obviously sends a signal, otherwise it will be ignored. When a / / filter, and the values are not the same, the content will be issued. / / in development, refresh UI is often used, only two times the data is not the same need to refresh the [[_textField.rac_textSignal distinctUntilChanged] subscribeNext:^ (ID x) {NSLog (“% @ @”, x);}]; take: from the beginning of a total of 1 times to take the signal / / N, *signal = [RACSubject subject] RACSubject create a signal; / / 2, signal processing take:1] subscribeNext:^, the subscription signal [[signal (ID x) {NSLog (“% @ @”, x); / /}]; 3 [signal sendNext:@1] [signal sendNext:@2] signal; takeLast:; signal, the last N prerequisite, the subscriber must call to complete, because only, know how many / 1, create signal. RACSubject *signal = [RACSubject subject] signal; / / 2, signal processing, signal [[signal takeLast:1] subscribeNext:^ subscription (ID x) {NSLog (“% @ @”, x);}] ; / / the 3 transmission signal [signal sendNext:@1]; [signal sendNext:@2]; [signal sendCompleted]; takeUntil: (RACSignal *): get the signal until a complete monitoring signal / / text box to change until the object is destroyed [_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal]; skip: (NSUInteger): skip several signals, do not accept. The first input / / said, will not be monitored to skip the first signal sent by the [[_textField.rac_textSignal skip:1] subscribeNext:^ (ID x) {NSLog (“% @ @”, x);}]; switchToLatest: for signalOfSignals (signal) signal, sometimes also will send a signal, in the signalOfSignals, the latest signal acquisition signalOfSignals send the. RACSubject *signalOfSignals = [RACSubject subject]; RACSubject *signal = [RACSubject subject]; / / get the signal signal signal signal recently, recently issued subscription. Note: switchToLatest / / only for the signal in the signal [signalOfSignals.switchToLatest subscribeNext:^ (ID x) {NSLog (“% @ @”, x); [signalOfSignals sendNext:signal]; [signal sendNext:@1]}];
  • 1.7 order of ReactiveCocoa operation method. Before doNext: Next, will first execute the Block doCompleted: implementation of the sendCompleted before the first execution of the Block [[[[RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@1]; [subscriber sendCompleted]; return nil;}] doNext:^ (ID x) {/ / [subscriber sendNext:@1]; Block NSLog will call this before (@ doNext) doCompleted:^{[subscriber;;}] / sendCompleted]; before will call this Block NSLog (@ doCompleted); subscribeNext:^;}] (ID x) {NSLog (“% @ @”, x);}];
  • 1.8 thread of ReactiveCocoa operation method. The deliverOn: content transfer is switched to the thread, the side effect is in the original thread, and the code in the block when the signal is created is called a side effect. SubscribeOn: content delivery and side effects are switched to the thread.
  • 1.9 ReactiveCocoa operation time. Timeout: timeout, can make a signal after a certain time, automatic error. RACSignal *signal = [[RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {return nil; timeout:1 onScheduler:[RACScheduler currentScheduler]]}]; [signal subscribeNext:^ (ID x) {NSLog (“% @ @”, x); error: (NSError *error)} ^ {/ / 1 will automatically call NSLog (@ “% @”, error);}] interval; time: every time signal [[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^ (ID x) {NSLog (“% @ @”, x); delay next}]; transmitting delay. RACSignal *signal = [[[RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@1]; return nil; delay:2] subscribeNext:^}] (ID x) {NSLog (“% @ @”, x);}];
  • 1.9 repeat of ReactiveCocoa operation method. Retry retry: as long as it fails, it will re execute the block in the created signal until it succeeds
__block int i = 0; [[[RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {if (I = = 10) {[subscriber sendNext:@1];}else{NSLog (@ "received error"); [subscriber sendError:nil]; i++ return nil;};}] retry] subscribeNext:^ (ID x) {NSLog (@ "% @ X". Error:^ (NSError);} *error {}]);
  • Replay replay: when a signal is subscribed multiple times, the content is repeated
RACSignal *signal = [[RACSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {[subscriber sendNext:@1]; [subscriber sendNext:@2]; return nil;}] replay]; [signal subscribeNext:^ (ID x) {NSLog (@ "the first subscription '% @", x);}]; [signal subscribeNext:^ (ID x) {NSLog ("second subscribers% @ @" x,}]);
  • Throttle throttling: when a signal is sent more frequently, you can use the throttle, in a certain period of time does not send the signal content, over a period of time to get the latest content. RACSubject *signal [RACSubject = subject]; _signal = signal; / / throttle, in a certain period of time (1s), does not receive any signal, after this time (1s) signal content to get the last sent out. [[signal throttle:1] subscribeNext:^ (ID x) {NSLog (“% @ @”, x);}];

2 introduction MVVM architecture ideas.

2.1 why the program structure: easy for programmers to develop and maintain code.

2.2 common architectural ideas:

  • MVC M: model V: view C: controller
  • MVVM M: model V: view + controller VM: view model
  • MVCS M: model V: view C: controller C: service class
  • VIPER V: view I: interactive display E: entity R: routing
    PS:VIPER architecture ideas

2.3 MVVM introduction

  • Model (M): saving view data.
  • View + controller (V): presentation + how to display
  • View model (VM): handle the business logic of the display, including the click of the button, the data request and analysis, etc..

3.ReactiveCocoa + MVVM Combat: login interface

  • 3.1 needs + analysis + steps
Requirements: two / * 1 monitoring the contents of the text box, a button click content allowed 2 default logon request. MVVM: implementation, analysis of all of the business logic interface: before all of the business logic interface before 1 to 2 within the framework of the MVVM controller in the controller of the entire business model also moved to VM. Each controller is a corresponding VM model. 1 steps: create a LoginViewModel class with the login interface business logic. This class of 2 there should be preserved account information, create a Account account should be preserved account information model 3.LoginViewModel Account model. 4 need to listen to the Account account and password changes, how to listen? 5 in the non RAC development, are used to assign, in RAC development, the need to change the development of thinking, change is bound by the assignment, can in the beginning initialization, to bind properties in the Account model, does not need to override the set method. 6 each time the value of the Account model, you need to determine whether the button click, do the processing in the VM model, with a click of a button can signal to the outside world. The 7 signal to judge the Account login account and password if there is value, using KVO to monitor the two value of the change, they aggregated into log signals 8. Monitor the click of a button, processed by VM, a RACCommand VM statement should give special treatment, on the business logic. 9 orders, the data package signal out signal 10 monitoring data transfer command 11 monitoring command execution time.
  • 3.2 controller code
@interface (ViewController) @property (nonatomic, strong) LoginViewModel *loginViewModel @property (weak, nonatomic); IBOutlet UITextField *accountField; @property (weak, nonatomic) IBOutlet UITextField *pwdField; @property (weak, nonatomic) IBOutlet UIButton *loginBtn; @end (LoginViewModel * loginViewModel) {if (_loginViewModel = = Nil) {_loginViewModel = [[LoginViewModel alloc] init]; return _loginViewModel};} / / view model binding - (void) bindModel {/ / to bind signal model as long as the account / text box will change, the assignment to account RAC (self.loginViewModel.account, account) = _accountField.rac_textSignal; RAC = _pwdField.rac_textSignal (self.loginViewModel.account, PWD); / / Bind the login button RAC (self.loginBtn, enabled) = self.loginViewModel.enableLoginSignal; / / [[_loginBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^ click the login button monitor (ID x) {/ / execution log event [self.loginViewModel.LoginCommand}]; execute:nil];}
  • 3.3 VM code
@interface LoginViewModel: NSObject @property (nonatomic, strong) Account *account; / / @property signal is allowed to log in (nonatomic, strong, readonly) RACSignal *enableLoginSignal; @property (nonatomic, strong, readonly) RACCommand *LoginCommand; @end @implementation LoginViewModel (Account * account) {if (_account = = Nil) {_account = [[Account alloc] init]; return _account};} - {if (instancetype) init (self = [super init]) {[self initialBind]}; return self;} / / initialization of the binding - (void) initialBind {/ / attribute value to monitor account changes, they aggregated into a signal. _enableLoginSignal [RACSignal = combineLatest:@[RACObserve (self.account, account), RACObserve (self.account, PWD)] reduce:^id (NSString *account, NSString *pwd) {return (account.length @ & & pwd.length;}]); / / treatment on business logic _LoginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal * (ID input) {NSLog (@ "click login" return [RACSignal createSignal:^RACDisposable (*); id< RACSubscriber> subscriber) {/ / imitation network delay (DISPATCH_TIME_NOW, dispatch_after (dispatch_time (int64_t) (0.5 * NSEC_PER_SEC)), dispatch_get_main_queue ([subscriber sendNext:@), ^{login successful]; / / data transfer is completed, must complete the call, Otherwise the command always in the implementation of the state of [subscriber sendCompleted];}); return nil;}];}]; / / [_LoginCommand.executionSignals.switchToLatest subscribeNext:^ monitoring data generated by the log (ID x) {if ([x isEqualToString:@ login successful]) {NSLog (@ "login successful");}}]; / / [[_LoginCommand.executing skip:1] subscribeNext:^ (login status monitoring ID x if ([x) {isEqualToNumber:@ (YES)]) {/ / ing / / login is... Use a mask that [MBProgressHUD showMessage:@ is "login..."];}else {/ / / / hide mask [MBProgressHUD successful login hideHUD];} }];}

4.ReactiveCocoa + MVVM two: network request data

  • 4.1 interface: here to give a friend a free network data interface, watercress. Can often be used to practice some of the network request small Demo.
  • 4.2 needs + analysis + steps
/ * needs: Douban request book information, url:https://api.douban.com/v2/book/search? Q= analysis: request, to the management of VM model: 1 steps to provide a model view controller (requesViewModel), business logic processing 2.VM interface provides a command, request processing business logic in the 3 creation command in block, will handle the request into a package a signal, when the request was successful, will pass data out. 4 the request data is successful, should be converted into a dictionary model, saved to the view model, the controller would like to use directly from the view model. 5 assuming that the controller wants to display the content to the tableView, the view model is directly used as the tableView data source, and all the business logic is given to the view model. * /
  • 4.3 controller code
@interface (ViewController) @property (nonatomic, weak) UITableView *tableView @property (nonatomic, strong); RequestViewModel *requesViewModel; @end @implementation ViewController (RequestViewModel * requesViewModel) {if (_requesViewModel = = Nil) {_requesViewModel = [[RequestViewModel alloc] init] return _requesViewModel;};} - {(void) viewDidLoad [super viewDidLoad] any additional setup; / / Do after loading the view, typically from a nib. tableView UITableView *tableView [[UITableView / / create alloc] = initWithFrame:self.view.bounds]; tableView.dataSource = self.requesViewModel; [self.view addSubview:tableView]; / / RACSignal *requesSiganl = [self.requesViewModel. request execution ReuqesCommand execute:nil] [requesSiganl subscribeNext:^; / / data acquisition request the (NSArray *x) {self.requesViewModel.models = x; [self.tableView reloadData];}]; @end}
  • 4.4 view model (VM) code
@interface RequestViewModel: NSObject< UITableViewDataSource> / / @property request command (nonatomic, strong, readonly) RACCommand *reuqesCommand; / / array @property (nonatomic, strong model, readonly NSArray *models; @end Implementation) @ RequestViewModel - (instancetype) init {if (self = [super init]) {[self initialBind];}} - (return self; void initialBind _reuqesCommand = [[RACCommand alloc]) {initWithSignalBlock:^RACSignal (ID * input) {RACSignal = [RACSignal * requestSignal * createSignal:^RACDisposable (id< RACSubscriber> subscriber) {NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; parameters[@ "Q"] = "@"; / / send a request to the [[AFHTTPRequestOperationManager "https://api.douban.com/v2/book/search" manager] GET:@ parameters:parameters success:^ (AFHTTPRequestOperation * _Nonnull operation, ID _Nonnull responseObject (NSLog) {@ "% @", responseObject); / / request / / successfully call the data using signal out [subscriber sendNext:responseObject]; [subscriber sendCompleted];} failure:^ (AFHTTPRequestOperation * _Nonnull operation NSError * _Nonnull error) {/ / the request failed call}]; return nil;}]; / / return data signal, the dictionary mapping data in the model of signal transmission. Go to the return [requestSignal map:^id (NSDictionary *value) {NSMutableArray *dictArr value[@ = "books"]; / / dictionary conversion model, traverse all the elements in the dictionary, all mapping model, and generates an array of NSArray *modelArr = [[dictArr.rac_sequence map:^id (ID value) {return [Book bookWithDict:value];}] array]; return modelArr;}];}]; #pragma} mark - UITableViewDataSource - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section {return self.models.count;} - (UITableViewCell *) tableView: (* UITableView) tableView cellForRowAtIndexPath: (NSIndexPath * indexPath) {static NSString *ID = "cell"; @ UITableV IewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell = = Nil) {cell [[UITableViewCell = alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];} Book *book = self.models[indexPath.row]; cell.detailTextLabel.text = book.subtitle; cell.textLabel.text = book.title; return cell @end;}

Contact information

(PS: also our company small brother, invite the IT session of the dedication and ability, competitive and energetic Geluyinghao joining together entrepreneurs, small details can click on code code small brother, brother micro-blog or micro-blog official, private chat I)