什么是MVC 什么是MVP
-
MVC
M代表:模型(Model)例如:User Student等等
V代表:UIView (视图)
Controller代表:UIViewController以及其子类(控制器)
存在问题:(UI层和数据层存在耦合) -
MVP
M代表:Model层(数据层:网络、数据库、文件等等)
V层:UIView+UIViewController以及子类
P层:控制器(设计初衷:为了将UI和数据完全进行分离) -
代码实现

- OC
- 搭建项目(登录实现)
- M层
发送网络请求
#import <Foundation/Foundation.h>
// 定义回调Block
typedef void(^Callback)(NSString *result);
@interface HttpUtils : NSObject
+ (void)post:(NSString *)name pwd:(NSString *)pwd callback:(Callback)callback;
@end```
import "HttpUtils.h"
@implementation HttpUtils
// 发送Post请求
-
(void)post:(NSString *)name pwd:(NSString *)pwd callback:(Callback)callback{
// 因为模拟这里直接返回
callback(@"登陆成功!");
return;NSURL *url = [[NSURL alloc] initWithString:@""];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = @"POST";
NSString *params = [NSString stringWithFormat:@"userName=%@&password=%@",name,pwd];
request.HTTPBody = [params dataUsingEncoding:NSUTF8StringEncoding];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"登录失败");
}else{
NSLog(@"登录成功!");
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
callback(result);
}
}];
}
@end```
#import <Foundation/Foundation.h>
#import "HttpUtils.h"
@interface LoginModel : NSObject
- (void)login:(NSString *)name pwd:(NSString *)pwd callback:(Callback)callback;
@end```
import "LoginModel.h"
@implementation LoginModel
// Model层: 数据层
// 包含:数据库模块、网络模块、文件等
- (void)login:(NSString *)name pwd:(NSString *)pwd callback:(Callback)callback{
[HttpUtils post:name pwd:pwd callback:^(NSString *result) {
// JSON解析 XML解析 其他数据解析
callback(result);
}];
}
@end```
数据解析
数据存储等
- V层 (UIView+UIViewController)
问题:M层如何和V层进行交互
解决方案:通过代理、协议、接口
定义LoginView协议
#import <Foundation/Foundation.h>
// V层和M层交互遵循的协议
@protocol LoginView <NSObject>
// 登录回调
- (void)onLoginResult:(NSString *)result;
@end```
- P层(Presenter)
实现原理:
M层和V层要进行关联,通过P层,那么如何通过P层来关联呢?
P层要持有M层对象的引用(指针)。同时还需要持有V层对象的引用(指针)。再进行关联。所以我们需要对M层和V层进行绑定(重点是绑定V层)
import <Foundation/Foundation.h>
import "LoginView.h"
@interface LoginPresenter : NSObject
// 绑定V层
- (void)attachView:(id<LoginView>)view;
// 解除绑定
- (void)detachView;
// 登录请求的方法(发起登陆)
- (void)login:(NSString *)name pwd:(NSString *)pwd;
@end```
#import "LoginPresenter.h"
#import "LoginModel.h"
@interface LoginPresenter()
// 持有M层的引用
@property (nonatomic, strong) LoginModel *loginModel;
// 持有V层的引用
@property (nonatomic) id<LoginView> loginView;
@end
@implementation LoginPresenter
- (instancetype)init{
if (self = [super init]){
// 初始化
_loginModel = [[LoginModel alloc] init];
};
return self;
}
- (void)attachView:(id)view{
_loginView = view;
}
- (void)detachView{
_loginView = nil;
}
// 登录请求的方法 (发起登录)
- (void)login:(NSString *)name pwd:(NSString *)pwd{
// 调用登录
[_loginModel login:name pwd:pwd callback:^(NSString *result) {
// 回调UI层
[_loginView onLoginResult:result];
}];
}
@end```
- 在V层调用P层 (关联 发起获取数据的请求 在协议回到方法中获取结果)
import "ViewController.h"
import "LoginView.h"
import "LoginPresenter.h"
@interface ViewController ()<LoginView>
@property (nonatomic, strong) LoginPresenter *loginPresenter;
@end
@implementation ViewController
-
(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.// 初始化P层
_loginPresenter = [[LoginPresenter alloc] init];
// 绑定协议
[_loginPresenter attachView:self];
}
// 实现协议登录回调
-
(void)onLoginResult:(NSString *)result{
// 更新UI
if (result != nil) {
NSLog(@"登录成功!返回的内容是%@",result);
}else{
NSLog(@"更新UI失败");
}
} -
(IBAction)loginClick:(UIButton *)sender {
[_loginPresenter login:@"Fage" pwd:@"123456"];
} -
(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.// 可以在这里解除协议 以免V层退出之后 还在更新UI
}
@end```
- 总结:
MVP的好处在于,解耦了Controller对数据层和View层的依赖。代码更加清晰,扩展性更好。拿以上登录模块来说,我们可以在任何地方任何V层来调用,只需持有一个P层即可。然后遵循协议,在点击方法中使用P层调用协议中的接口,即可得到登录结果。既避免了V层过度臃肿,又使代码拥有了良好的可读性以及可扩展性。
网友评论