Several commonly used architectures in iOS

MVC

MVC architecture relies on the relationship between Model, Controller, and View

Apple’s version of MVC

The data flow of Apple’s earliest MVC was centered on Controller, which served as a bridge between Model and View. Moreover, the data flow between Controller, Model and View was bidirectional

For example, a button click on the View is passed to the Controller, and the Controller retrieves data for the Model; The Model’s data is changed, and it’s displayed to the Controller to the View

In the interaction process of the three, View and Model are not directly related to each other

The most common display in iOS applications is a TableView, as shown in the sample code

// LLNews
@interface LLNews : NSObject

@property (copy, nonatomic) NSString *title;
@property (copy, nonatomic) NSString *content;
@end

@implementation LLNews

@end

// LLNewsViewController
@interface LLNewsViewController : UITableViewController

@end

@interface LLNewsViewController ()
@property (strong, nonatomic) NSMutableArray *newsData;
@end

@implementation LLNewsViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self loadNewsData];
}

- (void)loadNewsData
{
    self.newsData = [NSMutableArray array];
    
    for (int i = 0; i < 20; i++) {
        LLNews *news = [[LLNews alloc] init];
        news.title = [NSString stringWithFormat:@"news-title-%d", i];
        news.content = [NSString stringWithFormat:@"news-content-%d", i];
        [self.newsData addObject:news];
    }
}

#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.newsData.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NewsCell" forIndexPath:indexPath];
    
    LLNews *news = self.newsData[indexPath.row];
    
    cell.detailTextLabel.text = news.title;
    cell.textLabel.text = news.content;
    
    return cell;
}

#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"1111");
}

@end
Copy the code

Advantages: tableView and newsData are relatively independent and can be reused disadvantages: a lot of assignment code will be written in the Controller, Controller becomes too bloated

Varieties of MVC

After the variation of MVC data flow, Controller and View still interact with each other, and Controller will still get data to serve as Model. The difference is that the View can also hold the Model directly, and all three interact with each other

Let’s use sample code to illustrate the relationship between the three

// LLApp @interface LLApp : NSObject @property (copy, nonatomic) NSString *name; @property (copy, nonatomic) NSString *image; @end @implementation LLApp @end // LLAppView @class LLApp, LLAppView; @protocol LLAppViewDelegate <NSObject> @optional - (void)appViewDidClick:(LLAppView *)appView; @end @interface LLAppView : UIView @property (strong, nonatomic) LLApp *app; @property (weak, nonatomic) id<LLAppViewDelegate> delegate; @end @interface LLAppView() @property (weak, nonatomic) UIImageView *iconView; @property (weak, nonatomic) UILabel *nameLabel; @end @implementation LLAppView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { UIImageView *iconView = [[UIImageView alloc] init]; iconView.frame = CGRectMake(0, 0, 100, 100); [self addSubview:iconView]; _iconView = iconView; UILabel *nameLabel = [[UILabel alloc] init]; nameLabel.frame = CGRectMake(0, 100, 100, 30); nameLabel.textAlignment = NSTextAlignmentCenter; [self addSubview:nameLabel]; _nameLabel = nameLabel; } return self; } - (void)setApp:(LLApp *)app { _app = app; self.iconView.image = [UIImage imageNamed:app.image]; self.nameLabel.text = app.name; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { if ([self.delegate respondsToSelector:@selector(appViewDidClick:)]) { [self.delegate appViewDidClick:self]; } } @end // ViewController @interface ViewController () <LLAppViewDelegate> @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; LLAppView *appView = [[LLAppView alloc] init]; appView.frame = CGRectMake(100, 100, 100, 150); appView.delegate = self; [self.view addSubview:appView]; LLApp *app = [[LLApp alloc] init]; app.name = @"QQ"; app.image = @"QQ"; Appview. app = app; } #pragma mark - LLAppViewDelegate - (void)appViewDidClick:(LLAppView *)appView {NSLog(@" controller listen to appView click "); } @endCopy the code

Advantages: Controller will be relatively less load, reduce the View’s data assignment code, and external does not care about the View’s properties and what it does

Disadvantages: View and Model coupling is too high, will cause interdependence, can not be used separately, reduced reusability

MVP

The MVP architecture relies on the relationship between Model, Presenter, and View

A Presenter is more like a bridge between a Model and a View than a Controller, which only needs to manage a Presenter

Let’s use the above example to make adjustments. The sample code is shown below

LLApp and LLAppView are basically unchanged

// LLApp
@interface LLApp : NSObject
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *image;
@end

@implementation LLApp

@end

// LLAppView
@class LLAppView;

@protocol LLAppViewDelegate <NSObject>
@optional
- (void)appViewDidClick:(LLAppView *)appView;
@end

@interface LLAppView : UIView
- (void)setName:(NSString *)name andImage:(NSString *)image;
@property (weak, nonatomic) id<LLAppViewDelegate> delegate;
@end

@interface LLAppView()
@property (weak, nonatomic) UIImageView *iconView;
@property (weak, nonatomic) UILabel *nameLabel;
@end

@implementation LLAppView

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        UIImageView *iconView = [[UIImageView alloc] init];
        iconView.frame = CGRectMake(0, 0, 100, 100);
        [self addSubview:iconView];
        _iconView = iconView;
        
        UILabel *nameLabel = [[UILabel alloc] init];
        nameLabel.frame = CGRectMake(0, 100, 100, 30);
        nameLabel.textAlignment = NSTextAlignmentCenter;
        [self addSubview:nameLabel];
        _nameLabel = nameLabel;
    }
    return self;
}

- (void)setName:(NSString *)name andImage:(NSString *)image
{
    _iconView.image = [UIImage imageNamed:image];
    _nameLabel.text = name;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    if ([self.delegate respondsToSelector:@selector(appViewDidClick:)]) {
        [self.delegate appViewDidClick:self];
    }
}

@end
Copy the code

The extra Presenter and extracted Controller code are shown below

// LLAppPresenter @interface LLAppPresenter : NSObject - (instancetype)initWithController:(UIViewController *)controller; @end @interface LLAppPresenter() <LLAppViewDelegate> @property (weak, nonatomic) UIViewController *controller; @end @implementation LLAppPresenter - (instancetype)initWithController:(UIViewController *)controller { if (self = [super init]) { self.controller = controller; LLAppView *appView = [[LLAppView alloc] init]; appView.frame = CGRectMake(100, 100, 100, 150); appView.delegate = self; [controller.view addSubview:appView]; LLApp *app = [[LLApp alloc] init]; app.name = @"QQ"; app.image = @"QQ"; // Assign data [appView setName:app.name andImage:app.image]; } return self; } #pragma mark - MJAppViewDelegate - (void)appViewDidClick:(LLAppView *)appView {NSLog(@presenter); } @end // ViewController @interface ViewController () @property (strong, nonatomic) LLAppPresenter *presenter; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.presenter = [[LLAppPresenter alloc] initWithController:self]; } @endCopy the code

Advantages:

  • eachPresenterCorresponding to the respectiveModelandView
  • ModelandViewIt is also more independent and reusable
  • ControllerIt becomes more concise, just need to manage differentPresenterYou can

MVVM

The MVVM architecture relies on the relationship between Model, ViewModel and View, among which View includes View and Controller

The ViewModel is used to extract the business logic of the Controller and bind the Model to the View

After making changes to the MVC TableView example, the code looks like this

// LLNews @interface LLNews : NSObject @property (copy, nonatomic) NSString *title; @property (copy, nonatomic) NSString *content; @end @implementation LLNews @end // LLNewsViewModel @interface LLNewsViewModel : NSObject - (void)loadNewsData:(void (^)(NSArray *newsData))completion; @end @implementation LLNewsViewModel - (void)loadNewsData:(void (^)(NSArray *))completion { if (! completion) return; NSMutableArray *newsData = [NSMutableArray array]; for (int i = 0; i < 20; I++) {LLNews *news = [[LLNews alloc] init]; news.title = [NSString stringWithFormat:@"news-title-%d", i]; news.content = [NSString stringWithFormat:@"news-content-%d", i]; [newsData addObject:news]; } completion(newsData); } @end // LLNewsViewController @interface LLNewsViewController () @property (nonatomic, strong) LLNewsViewModel *newsVM;  @property (nonatomic, assign) NSArray *newsData; @end @implementation LLNewsViewController - (void)viewDidLoad { [super viewDidLoad]; self.newsVM = [[LLNewsViewModel alloc] init]; [self.newsVM loadNewsData:^(NSArray *newsData) { self.newsData = newsData; }]; } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.newsData.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NewsCell" forIndexPath:indexPath]; LLNews *news = self.newsData[indexPath.row]; cell.detailTextLabel.text = news.title; cell.textLabel.text = news.content; return cell; } #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"1111"); } @endCopy the code

Advantages: Controller does not need to write logical code, which is relatively less burden. MVVM can be combined with some responsive frameworks to make it easier to use

Architectural layering

Generally, we often divide into three layers, namely, the interface layer, the business layer and the data layer

MVC, MVP, AND MVVM architectures are all discussed at the interface level

The purpose of architectural layering is to reduce coupling and ease maintenance and development

Design patterns

What are design patterns

Design Pattern is a set of repeatedly used, code Design experience summary

The benefits of using design patterns include reusing code, making it easier for others to understand, and ensuring code reliability

Generally has nothing to do with programming language, is a set of relatively mature programming ideas

Several broad categories of design patterns

Design patterns fall into three broad categories

  • Creation pattern: Pattern of object instantiation, used to decouple the object instantiation process
    • Singleton pattern, factory method pattern, and so on
  • Structural pattern: Groups classes or objects together to form a larger structure
    • Proxy pattern, adapter pattern, composite pattern, decorator pattern, and so on
  • Behavioral patterns: How do classes or objects interact and divide responsibilities and algorithms
    • Observer mode, command mode, chain of responsibility mode, and so on

We’ll discuss it in more detail after a detailed overview