Simple popular understanding of the MVVM model

At present, the MVVM model is more developed and discussed in the mobile development model, and then there is the ReactiveCocoa framework. But MVVM design patterns do not necessarily mean using the ReactiveCocoa framework. After all, this framework is a heavy framework, and the general application doesn’t have to be so complex. Some time ago, the company app revision, the use of MVVM mode refactoring a bit of code, here is written down, just record my period of practice summary, I hope to try to say a little more clearly.

1, the difference between MVVM and MVC

MVC needless to say, it’s clear. MVVM, all the articles that speak MVVM will come up with this picture:

Simple popular understanding of the MVVM model

The difference between
and MVC is that there is a View Model in the middle. The previous MVC is view controller, dealing directly with model, and then filling the view with model. Here, MVVM’s view model separates view, controller/view, and model. The theory says here, then the question is:
1, what is the advantage of doing so?
2, how do you design this view model?

2, MVC, how do we write code?

For example, this common comment list:

Simple popular understanding of the MVVM model

this review list has three areas to note: one is dynamic line height, the other two is the number of points, depending on the size of the display, and three is the response to the comment, in front of which you want to add a different color “@XX””. The general MVC write code is this, the code structure is as follows:

Simple popular understanding of the MVVM model

below is the main code:

@implementation KTCommentsViewController - (void) viewDidLoad {[super viewDidLoad]; Do any additional setup after loading / the view from its nib. self.title = @ "comment list"; [self.tableView "KTCommentCell" registerNib:[UINib nibWithNibName:@ bundle:nil] forCellReuseIdentifier:kKTCommentCellIdentifier]; [self createData];} / / 1, data - (void) createData *array arrayWithCapacity:10] {NSMutableArray = [NSMutableArray; for (NSUInteger II = 0; II 20; < ++ii) {KTComment *comment = [[KTComment alloc] init]; comment.commentId = II + 1; [array addObject:comment]; comment.userName [NSString stringWithFormat:@ = "%lu". (unsigned, long) (II + 1)]; @ comment.userAvatar = "user_default"; NSMuta BleArray *strsArray = [NSMutableArray arrayWithCapacity:ii + 1] (JJ = 0; for NSUInteger; JJ < II + 1; ++jj) {[strsArray addObject:@ "this is the comment"]}; comment.content componentsJoinedByString:@ = [strsArray "," comment.commentTime "; date] = [NSDate; if (II% 3 = = 0) {comment.repliedUserId = 10; comment.repliedUserName =" Zhang San "; @ comment.favourNumber = 1000 * 3 * 10 * II;} else {comment.favourNumber}} * 3000 = II; self.commentsList = array;} #pragma mark - tableView - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section {return self.commentsList.count;} - (CGFloat) tableView: (UITableView *) tableView heightForRowAtIndexPath: (NS IndexPath * indexPath) {/ / 2, height KTComment *comment = [self.commentsList objectAtIndex:indexPath.row] calculation; CGFloat width = [UIScreen mainScreen].bounds.size.width - 10 - 12 - 35 - 10; CGFloat commnetHeight = [comment.content boundingRectWithSize:CGSizeMake (width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:14]} context:nil].size.height; return commnetHeight + 15 + 21;} - (UITableViewCell * tableView: * (UITableView) tableView) cellForRowAtIndexPath: (NSIndexPath *) indexPath KTCommentCell [tableView dequeueReusableCellWithIdentifier:kKTCommentCellIdentifier forIndexPath:indexPath] {*cell = KTComment; *comment = [self.commentsList objectAtIndex:in DexPath.row]; cell.comment = comment; return cell;}
/ / KTCommentCell - (void) setComment: (KTComment * comment) {_comment = comment; [_avatarImageView setImage:[UIImage imageNamed:comment.userAvatar]]; [_nameLabel setText:comment.userName]; [_timeLabel setText:[comment.commentTime ov_commonDescription]]; / / 3, to determine whether it is the logic of if comments (comment.repliedUserName.length > 0) {NSMutableAttributedString *attrContent = [[NSMutableAttributedString alloc] init]; NSString *header = [NSString stringWithFormat:@ comment.repliedUserName], "@%@"; NSAttributedString *reply = [[NSAttributedString alloc] initWithString:header attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:14], NSForegroundColorAttributeName: [UIColor blueColor]}]; app attrContent EndAttributedString:reply]; NSAttributedString *content = [[NSAttributedString alloc] initWithString:comment.content attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:14], NSForegroundColorAttributeName: [UIColor darkGrayColor]}]; appendAttributedString:content] [_commentLabel setAttributedText:attrContent]; attrContent;} else {[_commentLabel setText:comment.content];} / / 4, according to the points like the number display "transformation" after the points like the number of logical NSString *favourString = nil; if (comment.favourNumber = = 0) {favourString = else (comment.favourNumber if nil;} < {favourString = [NSString; 10000) stringWithFormat:@ "%lld like" comment.favourNumber] else if (comment.favourNumber <}; {10000) Float = floatNum (double) comment.favourNumber / 10000; favourString = [NSString stringWithFormat:@%.1f vanzan ", floatNum];} else {NSInteger intNum = comment.favourNumber / favourString = 10000; [NSString stringWithFormat:@"%ld vanzan ", (long) intNum] _favourLabel.text = favourString;}};

The MVC model, we can see the view controller and view (KTCommentCell) and Model (KTComment) is a direct deal, for data processing logic, for example, is directly written in view controller and view,
1, to obtain data: as the mark 1, if the local logic becomes complex for example, a data cache, to read the database, and then determine there is no data cache, if not request network data back even after parsing, then 1 code will become tedious.
2, high calculation: many applications involve high dynamic calculation, as marked 2 write here first of all is to let view controller this method also bloated, high frequent calls, so frequent calculation will seriously affect the sliding performance of tableView.
3, data processing logic: some attribute model is not used directly for view, such as the above 3, 4 two need attribute processing of model once again showed that MVC in the processing logic is written in view.
, this is just a simple example, a simple example, so there’s nothing wrong with it. However, if you encounter a more complex interface, this writing will lead to more and more view, controller and view code, and difficult to reuse, MVC becomes a fat view controller mode.

3, MVVM how to write?

MVVM is proposed to reduce the view controller and view view model will be the burden of the above mentioned data acquisition, high computing, data processing logic is separated from the view controller and view, while view controller/view and model separated.

#3.1, stripping line height calculation, data processing logic

As shown below, add view model:

Simple popular understanding of the MVVM model

below is the code example:

@interface KTCommentViewModel: NSObject @property (nonatomic, strong) KTComment *comment; / / how much is calculated according to the text for high @property (nonatomic, assign) CGFloat / cellHeight; according to whether the reply is, rich text @ property calculated (nonatomic, copy) NSAttributedString *commentContent; / / @property text according to the number of points like the calculated (nonatomic NSString *favourString, copy); @end @implementation KTCommentViewModel (void) setComment: (KTComment * comment) {_comment = comment; / / 1, calculation of high property save 2, depending on whether the reply / /, / / rich text calculated 3, according to the number of points like the calculated display text} @end

The code in 1, 2, and 3 here is basically equivalent to copying the code from 2, 3, and 4 in the previous view and view controller, which is omitted here. As you can see, the role of view model is:
1, dealing with model.
2, do some logical processing and calculation.
3, dealing with view, view, controller, and providing more intuitive data, such as the above cellHeight, commentContent, favourString, and other attributes.
this way, above 2, 3 and 4 of the code was moved to view model, view view controller, a lot of fresh, and responsibilities more clearly, for the high frequent calculation is avoided, because of high view model to cache, calculated only on the line again. Here are the changes in view, controller, and view:

- (CGFloat) tableView: (UITableView * tableView) heightForRowAtIndexPath: (NSIndexPath * indexPath) {KTCommentViewModel *viewModel = [self.commentsList objectAtIndex:indexPath.row]; return viewModel.cellHeight;} - (UITableViewCell *) tableView: (* UITableView) tableView cellForRowAtIndexPath: (NSIndexPath * indexPath) {KTCommentCell *cell = [tableView dequeueReusableCellWithIdentifier:kKTCommentCellIdentifier forIndexPath:indexPath]; KTCommentViewModel *viewModel = self.commentsList [objectAtIndex:indexPath.row] = viewModel; cell.commentViewModel; return cell;} / / KTCommentCell - (void) setCommentViewModel: (KTCommentViewModel * commentViewModel) {_commentViewModel = commentViewModel; [_avatarImageView setImage:[UIImage image Named:commentViewModel.comment.userAvatar]]; [_nameLabel setText:commentViewModel.comment.userName]; [_timeLabel setText:[commentViewModel.comment.commentTime ov_commonDescription]]; _commentLabel.attributedText = commentViewModel.commentContent; _favourLabel.text = commentViewModel.favourString;}
#3.2, stripped to obtain data logic

Create a list of view, model:,

Simple popular understanding of the MVVM model

code example is as follows:

@interface KTCommentListViewModel: NSObject, @property (nonatomic, copy) NSArray< KTCommentViewModel *> *commentViewModelList; - - (void) loadComments; @end

The responsibilities of KTCommentListViewModel are also clear, which is responsible for getting data, then creating a KTCommentViewModel object for each comment, and saving it in the list. Then the view controller can move the code that gets the data into this view model, and view controller just calls the methods and data provided by KTCommentListViewModel:

- (void) viewDidLoad {[super viewDidLoad]; Do any additional setup after loading / the view from its nib. self.commentListViewModel alloc] init] [self.commentListViewModel = [[KTCommentListViewModel; loadComments];}

4, summary

What is basically the first picture meaning. View and view controller have view model, view model has model, compared to MVC, the difference is that view and view controller through view model to operate data indirectly. The significance of this is that, for some of the more complex operation logic, can write view model and view controller, which simplifies view, view and view controller only display data and accept interactive events is good; in turn model update, view model update drive, and then drive the view and view controller change processing the logic of this intermediate can also be written in view model.
of course, for some relatively simple application interface, the use of MVC is more than enough, and do not need to use MVVM, what kind of
, but also to see the actual situation and personal preferences.

In addition, as @Noah1985 said, I did not add this example of model reverse drive view model and view/view controller part, and can not be considered a complete MVVM, in practical applications can be coupled with RAC. But if you can sort out and update callback mechanism, there is no RAC.