Easy to understand illustrations MVVM and RAC bidirectional binding introduction (with Demo)

Source: Internet
Author: User
Tags call back
Preface

An introduction to the MVVM of a predecessor
In fact, MVVM is the evolutionary version of MVC, relative to the bloated controller, more and more code, some people have used a new design pattern, actually see a long time also nothing, popular point to speak, In fact, the previous controller inside the code logic all transplanted into the viewmodel inside, as opposed to previously, the controller is also classified as a view of a class, then he and view will have their own viewmodel to deal with the logic, And ViewModel must have model, such a relationship makes the controller code will be reduced a lot, processing up a class, its own design mode inside there are agents, notices, KVO and so on, different business corresponding to different design patterns, personal understanding in order to reduce the controller code, introduced a new class, Then the interaction of the class becomes more troublesome, so the RAC appears, he helps us directly manage the Apple's set of data processing design pattern, unified with its "signal flow" to carry out, who knows ah ...

Bidirectional binding
1.model-->view This flow is simple, after you request the data, through the block callback, the final update UI
2.view-–>model reverse binding is the same, View trigger events, update the opposite ViewModel inside the binding data source, such as login registration of the TextField, you enter and delete, your Model field will correspond to update, when you submit, Reading the ViewModel field is the most recent data that has been updated. This is a way that I personally feel the other one is easier to understand, such as when you choose a cell or a point of praise, view event trigger, update bound ViewModel field, have ViewModel controller, use Racobserve to read the field switch, If you hear yes, refresh the corresponding page UI

Simply look at the mvvm you understand.

Effect chart



Picture and text flicker effect transfer door
Introduction to the first process of scintillation-effect RAC->racsignal

A lot of basic introduction on the Internet, here mainly talk about the process
1. If you use racsignal to create the signal (the internal block has the signal to send and cancel the signal callback, why is 3 and 4, the reason is later)

1. Create signal
racsignal *signal = [racsignal createsignal:^racdisposable * (id<racsubscriber> subscriber) {
/ /3. Send signal
[subscriber sendnext:@ "mkj"];
[subscriber sendcompleted];
4. Cancellation signal, if the signal wants to be canceled, must return a racdisposable
//When the signal is manually or automatically unsubscribe after the callback here, for some resource release return
[racdisposable disposablewithblock:^{
NSLog (@ "unsubscribe");
}];

Note: The internal code of the method created above is mainly due to the creation of a subclass->racdynamicsignal integrated into racsignal, and then
It is instantiated by a static method, and the object block is stored with the passed in task block.

+ (Racsignal *) createsignal: (racdisposable * (^) (id<racsubscriber> Subscriber)) Didsubscribe {
    Racdynamicsignal *signal = [[Self alloc] init];
    Signal->_didsubscribe = [didsubscribe copy];
    return [Signal setnamewithformat:@ "+createsignal:"];
}

2. The signal racsignal (subclass Racdynamicsignal) is created to invoke the second step [Signale subscribenext:^{}]; Subscribe to the signal, internal code

Racsubscriber *o = [Racsubscriber subscriberwithnext:nextblock error:null completed:null];
    return [self subscribe:o];

Note: Here the RAC designer hides the Racsubscriber from us, exposes racsignal, and all internal work is delivered by Racsubsriber.
If you point in again, the signal passed here will determine whether the block that was passed in the previous creation was empty, and if there was a task, direct callback block

Racdisposable *innerdisposable = self.didsubscribe (subscriber);

3. Now someone has subscribed to the block and then triggered the task and then called

[Subscriber sendnext:@ "mkj"];
[subscriber sendcompleted];

The internal code final invocation method is as follows
-(void) Sendnext: (id) value {
    @synchronized (self) {
        void (^nextblock) (id) = [self.next copy ];
        if (Nextblock = = nil) return;

        Nextblock (value);
    }
}
Nextblock tasks when the final callback is to the subscription

4. This dispensable, returns a racdisposable, cancels the resource release for the subscription

Summary: Compare him to a factory, when you need to open the production line (create a signal, with a task), at this time you do not have workers, do not go to your task
The signal will not be transmitted, and when you have a worker (that is, subscribe to the signal), this time the assembly line began to process, which is a personal understanding of the cold signal mode
The cold signal can also be understood as the signal is not subscribed, understood as the signal inside the task is not going to be, only the subscriber to join, the signal will become a hot signal
That's what this thing is. To manually open the signal RAC the second kind of process introduction->racsubject (Inheritance and racsignal)

1. Create a signal
Racsubject *subject = [racsubject subject];
The method is different from the way it was created, and his instantiation only creates an array of subscribers that are dedicated to storing the subscription signal.


2. Subscribe to the Signal

[Subject subscribenext:^ (ID x) {
///When the signal is Sendnext it will call back
NSLog (@ "%@", x);
}];
This method is also different from the above, racsubject the object will put the subscriber into the previously created array, and then do nothing

3.[subject Sendnext:value];

Internal code
[self enumeratesubscribersusingblock:^ (id<racsubscriber> subscriber) {
        [subscriber SendNext: value];
    };
As you can see, when he calls Sendnext, the array is traversed, and a message is sent to the Subscriber.

Summary: In fact this is called the heat signal mode, or take the factory to do analogy, racsubject is whether you have no one to subscribe, I plant 24 hours to open the assembly line
I care if you have no one to process, someone is coming, I will use an array to register, the signal comes when you are responsible for receiving the task, no one when I was like my staff
The roster is empty, but the production, but no one to do things, then here's the RAC signal flow is no one to deal with, will be discarded

Knowledge points: Distinguishing Racsubject from racsignal
1. I personally understand that the former is cold signal mode, need someone to subscribe to open the hot signal, the latter is the hot signal default, whether you have no subscription

2. The former is in fact once someone subscribe, will do a corresponding set of signal tasks, and then make a callback, can be understood as someone's time to start the task, when no one hangs the machine
Yes, I'm simply understanding it as a proxy, the latter is a thermal signal, the signal is responsible for collecting the subscriber array, sending signals back to traverse the Subscriber, one by one to perform the task
You can interpret it as a notice, I charge you have not received, I still send, no one will discard

3. The former individual is used for the network request, the latter carries on the similar proxy or the notification data transmission pattern, thus may simply understand, the RAC actually is the Apple's set
Delegate,notification,kvo and so on a series of methods combined, more comfortable to use it

4. Then MVVM mode, itself is more than a viewmodel, interaction requires more design mode assistance, RAC solves this problem, directly with this design pattern to engage in
The code for data passing and listening is much clearer.

Now that the process of RAC has been known, the demo walks ... MVVM + RAC Sample Demo

1. Signal transmission using the network request

2. Kvo observation of properties with Racobserve macros

3. Callback of data using Racsubject

4. The traversal of asynchronous arrays and dictionaries (printed ractuple) with Racsequence

5.rac–>combinelatest method for simple multiple-input box login Registration page Simulation


Let's take a look at the relationship between the various classes in the demo


1. First look at the base class with MVVM (Mkjbaseviewcontroller)

BASEVC base ViewModel
//Subclass overrides can overwrite type
@property (nonatomic,strong,readonly) Mkjbaseviewmodel *viewmodel;

/**
 Unique initialization method

 @param viewModel incoming ViewModel
 @return Instantiation Controller Object
/-(Instancetype) Initwithviewmodel :(Mkjbaseviewmodel *) ViewModel;

/**
 Layout UI Subclass Rewrite
 *
/(void) setuplayout;

/**
 Request network data binding data Subclass rewrite
 * *
-(void) setupbinding;

/**
 Set the data callback, click on the event processing  Subclass Rewrite
 * *
-(void) SetupData;

When initialized
mkjdemoviewmodel *viewmodel = [[Mkjdemoviewmodel alloc] init];
            Mkjdemoviewcontroller *DEMOVC = [[Mkjdemoviewcontroller alloc] initwithviewmodel:viewmodel];
            [Self.navigationcontroller PUSHVIEWCONTROLLER:DEMOVC Animated:yes];

2. A second look at the base class of Tableviewcontroller
The basic implementation is the same as the generic controller with TableView, except that the logic and data of the agent are given to the ViewModel

To the subclass implementation, passing the final cell class-(Class) Cellclassforrowatindexpath: (Nsindexpath *) Indexpath {@throw [nsexception exceptionwithn ame:@ "Abstract method not implemented" Reason:[nsstring stringwithformat:@ "%@ must implement abstract method%@", [Self Class],nsstrin
Gfromselector (_cmd)] userinfo:nil]; #pragma mark-tableview datasource//to ViewModel to implement-(Nsinteger) Numberofsectionsintableview: (UITableView *) Tablevie

w {return [Self.viewmodel numberofsections];} -(Nsinteger) TableView: (UITableView *) TableView numberofrowsinsection: (nsinteger) Section {return [Self.viewmodel num
Berofrowinsection:section]; }-(CGFloat) TableView: (UITableView *) TableView heightforheaderinsection: (nsinteger) Section {return [Self.viewmodel
Heightforheaderinsection:section]; }-(UIView *) TableView: (UITableView *) TableView viewforheaderinsection: (nsinteger) Section {return [Self.viewmodel V
Iewforheaderinsection:section]; }-(UITableViewCell *) TableView: (UITableView *) tabLeview Cellforrowatindexpath: (Nsindexpath *) Indexpath {Mkjbasetableviewcell *cell = [[Self Cellclassforrowatindexpath
    : Indexpath] Cellfortableview:tableview Viewmodel:[self.viewmodel Cellviewmodelforrowatindexpath:indexpath]];
    Cell.selectionstyle = [Self.viewmodel Tableviewcellselectionstyle];
return cell; }-(CGFloat) TableView: (UITableView *) TableView Heightforrowatindexpath: (Nsindexpath *) Indexpath {CGFloat height = t
    Ableview.rowheight; NSNumber *calculateheight = [[Self Cellclassforrowatindexpath:indexpath] calculaterowheightwithviewmodel:[
    Self.viewmodel Cellviewmodelforrowatindexpath:indexpath]];
    if (calculateheight) {height = Calculateheight.floatvalue;

return height; }

3. The final top of the Viewcontroller core code, and finally left just so little code, thin body not ....

Basic layout code, by the way set a racobserve
-(void) setuplayout
{
    [super setuplayout];
    @weakify (self);
    [Racobserve (Self.viewmodel, Isneedrefresh) subscribenext:^ (ID x) {
        @strongify (self);
        if ([x Boolvalue]) {
            [Self.tableview reloaddata];
        }
    ];

}
ViewModel for network requests
-(void) setupbinding
{
    [super setupbinding];
    @weakify (self)
    [Self.viewmodel sendrequest:^ (ID entity) {
        @strongify (self);
        [Self hideloadingviewfooter];
        [Self.tableview reloaddata];

    } failure:^ (Nsuinteger errcode, NSString *errormsg) {

    }];
}
Returns the corresponding Cellclass
-(Class) Cellclassforrowatindexpath: (Nsindexpath *) Indexpath
{return
    [ Mkjdemotableviewcell class];

4. To see what ViewModel is doing, the core or network request, the RAC Signal Stream network request

Network request External-(void) SendRequest: (mkjrequestsucceed) succeedblock failure: (mkjrequestfailure) Failblock {[Self.model req Uestdemodataswithpage:[self.currentpage IntegerValue] MaxTime:self.currentMaxTime] subscribenext:^ (ID data) {if (
            Data) {self.entity = data;
                    [Self handlePagingEntities:self.entity.list totalcount:@ (self.entity.info.count) Cellviewmodelclass:[mkjdemotableviewcellviewmodel class] MaxTime:self.entity.info.ma
        Xtime]; }!succeedblock?
    : Succeedblock (data);
}]; }//Network request Internal-(racsignal *) getrequestwithurlstring: (NSString *) urlstring parametersdictionary: (nsdictio
    nary *) paraterdictionary Parserentityclass: (Class) Parseentityclass {//Create a new racsinal based on an asynchronous request @weakify (self) return [racsignal createsignal:^racdisposable * (id<racsubscriber> subscriber) {@strongif

        Y (self); [Self. Httphelper getrequestwithurlstring:urlstring Parametersdictonary:paraterdictionary
                                       Entityclass:parseentityclass completeblock:^ (id data) {
                                       [Subscriber Sendnext:data];
        [Subscriber sendcompleted];

        }];
    return nil;
}]; Based on the RAC logic described above, the external subscriber becomes a hot signal and then calls the block that creates the signal, Sendnext the callback after the network request is designed, and then assembles the model in ViewModel. Carry out the external tableview reload. And then call the proxy method again, will again into the viewmodel inside to get the data that has been assembled back to TableView's DataSource, OK

5.Cell also configured the corresponding Cellviewmodel, that is, after the RAC network request back, the entity model, with Cellviewmodel to assemble, just put the data model before the array, Used to hold the cellviewmodel of the data model, understand that, ViewModel owns model, can handle the logical processing of data





I finally got it. No BB show me the code, this is not clear, the need for students or directly to see the demo bar, the final logical conversion is above the MVVM effect map, understand it, is nothing more than a design idea, but with the RAC is really good ...

I personally also like to see the demo, the need or directly to open the bar
Correct demo Address

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.