美文网首页ios 知识点
iOS的MVVM框架模式

iOS的MVVM框架模式

作者: WorldPeace_hp | 来源:发表于2018-09-25 11:53 被阅读3184次

前言:iOS的MVVM如何工作呢?各自的职责是什么呢?首先我们先来介绍一下纯粹的MVVM架构模式,再来介绍MVVM的双向绑定。

来看一下MVVM的工作原理图: mvvm.png

MVVM的通讯关系:

1.View与Model是不直接通讯的。
2.ViewController与Model是不直接通讯的。
3.View只与ViewController/View Model两者发生关系。
4.Model只与View Model通讯。

责任划分:

Model:业务逻辑处理、数据控制(本地数据、网络加载数据)。
View:显示用户可见得视图控件、与用户交互事件。
ViewModel:是组织生成和维护的视图数据层。在这一层开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。
ViewController:界面的生命周期控制和业务间切换控制。

工程目录结构:

mvvm.png

MVVM代码实例:

Model:

#import "MAnimalEntity.h"
@protocol MAnimalModelDelegate;

@interface MAnimalModel : NSObject

@property (nonatomic,weak) id<MAnimalModelDelegate> delegate;
@property (nonatomic,strong) NSArray <MAnimalEntity*>*dataSource;

- (void)downloadImageWtihEntity:(MAnimalEntity *)entity;

@end

@protocol MAnimalModelDelegate<NSObject>
- (void)animalShowImage:(MAnimalEntity *)entity row:(NSInteger)row;
@end

#import "MAnimalModel.h"

@implementation MAnimalModel

- (instancetype)init {
    self = [super init];
    if (self) {
        [self loadDataSource];
    }
    return self;
}

- (NSArray *)loadJson {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"jsonString" ofType:@"json"];
    NSData *jsonData = [NSData dataWithContentsOfFile:path];
    NSError *error = nil;
    id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:(NSJSONReadingMutableLeaves) error:&error];
    if ([jsonObject isKindOfClass:[NSArray class]]) {
        return jsonObject;
    }
    else {
        return nil;
    }
}

- (void)loadDataSource {
    NSArray *array = [self loadJson];
    NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:array.count];
    
    for (NSDictionary *dictionary in array) {
        MAnimalEntity *entity = [[MAnimalEntity alloc] init];
        entity.identifier = [[NSDate date] timeIntervalSince1970];
        entity.imageUrl = [dictionary objectForKey:@"url"];
        entity.name = [dictionary objectForKey:@"name"];
        entity.summary = [dictionary objectForKey:@"summary"];
        
        [mutableArray addObject:entity];
    }
    
    _dataSource = mutableArray;
}

- (void)downloadImageWtihEntity:(MAnimalEntity *)entity {
    if (entity.isLoading || !entity.imageUrl || entity.imageUrl.length == 0) {
        return;
    }
    
    entity.isLoading = YES;
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSURL *imageURL = [NSURL URLWithString:entity.imageUrl];
        NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
        if (imageData) {
            entity.imageData = imageData;
        }
        NSLog(@"imageData = %@",imageData);
        
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.delegate && [self.delegate respondsToSelector:@selector(animalShowImage:row:)]) {
                NSInteger row = [self.dataSource indexOfObject:entity];
                [self.delegate animalShowImage:entity row:row];
            }
        });
    });
}

@end

//MAnimalEntity
@interface MAnimalEntity : NSObject

@property (nonatomic,assign) NSInteger identifier;
@property (nonatomic,strong) NSData *imageData;
@property (nonatomic,copy) NSString *imageUrl;
@property (nonatomic,copy) NSString *name;
@property (nonatomic,copy) NSString *summary;
@property (nonatomic,assign) BOOL isLoading;

@end
#import "MAnimalEntity.h"

@implementation MAnimalEntity

@end

View:

//TableView
#import "MAnimalViewModel.h"

@interface MAnimalTableView : UITableView

@property (nonatomic,strong) MAnimalViewModel *viewModel;

- (void)refreshData;

@end

#import "MAnimalTableView.h"

#import "MAnimalCell.h"

@interface MAnimalTableView()<UITableViewDelegate,UITableViewDataSource,MAnimalViewModelDelegate>

@end

@implementation MAnimalTableView

- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
    self = [super initWithFrame:frame style:style];
    if (self) {
        self.delegate = self;
        self.dataSource = self;
        
        self.viewModel = [[MAnimalViewModel alloc] init];
        self.viewModel.delegate = self;
    }
    return self;
}

- (void)refreshData {
    [self.viewModel reloadData];
}

#pragma mark -
#pragma mark -- MAnimalViewModel Delegate
- (void)viewModel:(MAnimalViewModel *)viewModel reloadRow:(NSInteger)row {
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
    [self reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}

- (void)reloadDataWithViewModel:(MAnimalViewModel *)viewModel {
    [self reloadData];
}

#pragma mark -
#pragma mark -- Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.viewModel.dataSource.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *reuseIdentifier = @"reuseIdentifier";
    MAnimalCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    if (!cell) {
        cell = [[MAnimalCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
    }
    
    MAnimalViewEntity *entity = [_viewModel animalEntityWitIndexPath:indexPath.row];
    
    cell.textLabel.text = entity.name;
    cell.detailTextLabel.text = entity.summary;
    [cell showImageWithData:entity.imageData];
    
    return cell;
}

#pragma mark -
#pragma mark -- UITableView Delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive
                                                                            title:@"Delete"
                                                                          handler:^(UITableViewRowAction *action,
                                                                                    NSIndexPath *indexPath) {
                                                                              [self.viewModel deleteWithRow:indexPath.row];
                                                                              
                                                                              [tableView beginUpdates];
                                                                              [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
                                                                              [tableView endUpdates];
                                                                          }];
    return @[deleteAction];
}


@end

//Cell
@interface MAnimalCell : UITableViewCell

- (void)showImageWithData:(NSData *)data;

@end

#import "MAnimalCell.h"

@implementation MAnimalCell

- (void)awakeFromNib {
    [super awakeFromNib];
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

- (void)showImageWithData:(NSData *)data {
    if (data) {
        self.imageView.image = [UIImage imageWithData:data];
    }
}

@end

ViewModel:

#import "MAnimalViewEntity.h"
@protocol MAnimalViewModelDelegate;

@interface MAnimalViewModel : NSObject

@property (nonatomic,weak) id<MAnimalViewModelDelegate> delegate;
@property (nonatomic,strong,readonly) NSMutableArray <MAnimalViewEntity*>*dataSource;

- (MAnimalViewEntity *)animalEntityWitIndexPath:(NSInteger)row;
- (void)deleteWithRow:(NSInteger)row;
- (void)reloadData;

@end

@protocol MAnimalViewModelDelegate<NSObject>
- (void)viewModel:(MAnimalViewModel *)viewModel reloadRow:(NSInteger)row;
- (void)reloadDataWithViewModel:(MAnimalViewModel *)viewModel;
@end

#import "MAnimalViewModel.h"

#import "MAnimalModel.h"

@interface MAnimalViewModel()<MAnimalModelDelegate>
@property (nonatomic,strong) MAnimalModel *animalModel;
@end

@implementation MAnimalViewModel

- (instancetype)init {
    self = [super init];
    if (self) {
        _animalModel = [[MAnimalModel alloc] init];
        _animalModel.delegate = self;
        
        [self reloadData];
    }
    return self;
}

- (MAnimalViewEntity *)animalEntityWitIndexPath:(NSInteger)row {
    MAnimalViewEntity *viewEntity = [_dataSource objectAtIndex:row];
    
    if (_animalModel.dataSource.count > row) {
        MAnimalEntity *entity = [_animalModel.dataSource objectAtIndex:row];
        [_animalModel downloadImageWtihEntity:entity];
    }
    
    return viewEntity;
}

- (void)animalShowImage:(MAnimalEntity *)entity row:(NSInteger)row {
    MAnimalViewEntity *viewEntity = [_dataSource objectAtIndex:row];
    viewEntity.imageData = entity.imageData;
    
    if (_delegate && [_delegate respondsToSelector:@selector(viewModel:reloadRow:)]) {
        [_delegate viewModel:self reloadRow:row];
    }
}

- (void)deleteWithRow:(NSInteger)row {
    [_dataSource removeObjectAtIndex:row];
}

- (void)reloadData {
    MAnimalViewEntity *vieweEtity = nil;
    
    NSMutableArray *mutableArray = [NSMutableArray array];
    for (MAnimalEntity *entity in _animalModel.dataSource) {
        vieweEtity = [[MAnimalViewEntity alloc] init];
        vieweEtity.identifier = entity.identifier;
        vieweEtity.imageData = entity.imageData;
        vieweEtity.name = entity.name;
        vieweEtity.summary = entity.summary;
        [mutableArray addObject:entity];
    }
    
    _dataSource = mutableArray;
    
    if (_delegate && [_delegate respondsToSelector:@selector(reloadDataWithViewModel:)]) {
        [_delegate reloadDataWithViewModel:self];
    }
}

@end

@interface MAnimalViewEntity : NSObject

@property (nonatomic,assign) NSInteger identifier;
@property (nonatomic,strong) NSData *imageData;
@property (nonatomic,copy) NSString *name;
@property (nonatomic,copy) NSString *summary;

@end

#import "MAnimalViewEntity.h"

@implementation MAnimalViewEntity

@end

ViewController:

#import <UIKit/UIKit.h>

@interface MAnimalViewController : UIViewController

@end

#import "MAnimalViewController.h"

#import "MAnimalTableView.h"

@interface MAnimalViewController ()

@end

@implementation MAnimalViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.title = @"MVVM";
    
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Refresh"
                                                                              style:UIBarButtonItemStylePlain
                                                                             target:self
                                                                             action:@selector(refreshAction)];
    
    MAnimalTableView *tableView = [[MAnimalTableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
    self.view = tableView;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)refreshAction {
    MAnimalTableView *tableView = (MAnimalTableView *)self.view;
    [tableView refreshData];
}

@end

Demo:https://github.com/PeaceWanghp/iOSArchitecture

相关文章

网友评论

    本文标题:iOS的MVVM框架模式

    本文链接:https://www.haomeiwen.com/subject/bkpnyftx.html