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:
- each
Presenter
Corresponding to the respectiveModel
andView
Model
andView
It is also more independent and reusableController
It becomes more concise, just need to manage differentPresenter
You 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