个人对于MVP思路的理解,就是开发过程中,数据和界面之间的交互,使用Presenter层管理,较于MVC模式:获取数据,构建对象,在控制器里赋值更新界面;MVP模式思路在获取数据,构造对象后,不直接在控制器中做界面交互逻辑,而是使用控制器层管理,将业务逻辑独立出来,这样便于代码的后期维护,同时降低了控制器的负担以及数据模型和控制器、界面之间的耦合性。
本篇文章以登录界面为例,使用ios的OC语言展示我对于MVP的理解:
登录界面:
首先创建一个空的项目,名为MVPDemoOC,
建立一个名为Classes的文件夹,代码将在该文件夹中:
文件夹UI放置控制器,Biz放置业务逻辑,Model放置数据模型,Presenter放置控制器相应的管理者,View放置管理者和控制器的交互层(注意:文件夹View区别于UIView,文章中实例并未用到UIView文件夹,但在实际开发中,例如TableViewController的cell应放置在UIView中)
在Main.stroyboard中搭建界面,并在ViewController中连接,代码:
#import "ViewController.h"
@interface ViewController ()
{
__weak IBOutlet UITextField *userName;
__weak IBOutlet UITextField *passWord;
__weak IBOutlet UIActivityIndicatorView *activityBar;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
activityBar.hidden = true ;
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)loginClick:(UIButton *)sender {
}
- (IBAction)clearClick:(UIButton *)sender {
}
@end
建立登录的数据模型(UserModel):
在UserModel.h中,代码:
#import <Foundation/Foundation.h>
@interface UserModel : NSObject
@property ( nonatomic , copy ) NSString * username;
@property ( nonatomic , copy ) NSString * password;
@end
在UserModel.m中,代码:
#import "UserModel.h"
@implementation UserModel
@end
建立管理者ViewPresenter的类,包含.h和.m文件,继承NSObject
建立管理者和控制器之间的交互View层,名为MainView。分析:由于View层是用于控制器和管理者(ViewPresenter)的交互,对于管理者,对MainView调用的是一个MainView对象;而在控制器中,需要实现MainView的方法,即为协议。所以MainView可以用协议来实现,在代码中,只需创建MainView.h文件即可(文章后面创建协议均为.h文件,不做单独描述)。代码:
@protocol MainView <NSObject>
@end
现在项目目录如图:
至此,进行分析如下:
界面需要输入账号,密码,然后点击登录时,加载动画展示,做登录请求,判断账号密码是否正确,返回成功或是失败,加载动画隐藏。
点击清空按钮,清空账号,清空密码。
管理者需要有登录和清空的事件,还需使用MainView对象,进行和控制器的交互,在控制器中创建管理者时,还需设置交互的View层链接,即为persenter.maivView = self ,该代码可以在管理者对象创建的构造函数中直接实现。则在代码ViewPresenter.h中:
#import <Foundation/Foundation.h>
#import "MainView.h"
@interface ViewPresenter : NSObject
#pragma mark - 介于控制器和管理者的交互对象
@property ( nonatomic , assign ) id<MainView> mainView;
#pragma mark - 控制器的登录事件
- (void) login ;
#pragma mark - 控制器的清空事件
- (void) clear ;
#pragma mark - 管理者的构造函数
- (instancetype)initWithMainView : (id<MainView>) mainView ;
@end
在ViewPresenter.m的实现中,登录需要使用_mainView对象加载蒙版动画,获得账号,获得密码,登录成功或是失败,需要_mainView隐藏加载动画;在管理者清空动作中,需要_mainView对象清空账号,清空密码。以上分析后,可以确定在MainView.h中(即View协议层中),需要实现代码:
@protocol MainView <NSObject>
#pragma mark - 展示加载动画
- (void) showProgress ;
#pragma mark - 隐藏加载动画
- (void) dismiss ;
#pragma mark - 获得账号
- (NSString *) getUserName ;
#pragma mark - 获得密码
- (NSString *) getPassWord ;
#pragma mark - 清空账号
- (void) clearUserName ;
#pragma mark - 清空密码
- (void) clearPassWord ;
@end
管理者ViewPresente.m中代码如下:
#import "ViewPresenter.h"
@implementation ViewPresenter
#pragma mark - 管理者的构造函数
- (instancetype)initWithMainView : (id<MainView>) mainView {
if (self = [super init]) {
_mainView = mainView ;//设置管理者的MainView
}
return self ;
}
#pragma mark - 控制器的登录事件
- (void) login {
[_mainView showProgress];
//登录
}
#pragma mark - 控制器的清空事件
- (void) clear {
[_mainView clearUserName];
[_mainView clearPassWord];
}
@end
登录时的业务逻辑层分析:需要登录的对象,调用一个登录函数,传参为账户。密码。监测登录成功或是失败。
则在业务层创建一个登录用到的类,名称UserLogin,同时创建登录结果的监听协议LoginListener。
在UserLogin.h中,代码:
#import <Foundation/Foundation.h>
#import "LoginListener.h"
@interface UserLogin : NSObject
/**
* 登录
*
* @param userName 账号
* @param passWord 密码
* @param loginListener 登录的监听
*/
- (void) loginWithUserName:(NSString *) userName
WithPassWord:(NSString *) passWord
WithLoginListener: (id<LoginListener>) loginListener ;
@end
在LoginListener.h中,登录监听的结果有两种:成功,失败,监听结果可以传参,成功时返回登录的UserModel对象,失败返回失败的信息字符串。代码如下:
@class UserModel ;
@protocol LoginListener <NSObject>
- (void) Failure:(NSString *) errormessage ;
- (void) Sucess: (UserModel *) model ;
@end
在UserLogin.m中,代码如下:
#import "UserLogin.h"
#import "UserModel.h"
@implementation UserLogin
/**
* 登录
*
* @param userName 账号
* @param passWord 密码
* @param loginListener 登录的监听
*/
- (void) loginWithUserName:(NSString *) userName
WithPassWord:(NSString *) passWord
WithLoginListener: (id<LoginListener>) loginListener {
//此处模拟异步线程
dispatch_queue_t dqt = dispatch_queue_create("login", nil);
dispatch_async(dqt, ^{
//异步线程中
sleep(2);//线程阻塞2秒,用于展示加载动画
//此处返回主线程
dispatch_queue_t maindqt = dispatch_get_main_queue() ;
dispatch_async(maindqt, ^{
//主线程中
//判断登录的结果
if ([userName isEqualToString:@"fei"]&&[passWord isEqualToString:@"123"]) {
//登录成功
UserModel * m = [[UserModel alloc]init];
m.username = userName;
m.password = passWord ;
[loginListener Sucess:m];
} else {
//登录失败
[loginListener Failure:@"你的账号或是密码不正确"];
}
});
});
}
@end
业务逻辑层处理完成,在管理者ViewPresenter中,实现登录调用需声明登录UserLogin的变量,并在构造函数中实例化该变量,并且ViewPresenter需要遵循登录监听的协议LoginListener,代码如下
#import "ViewPresenter.h"
#import "UserLogin.h"
#import "UserModel.h"
@interface ViewPresenter ()<LoginListener,UIAlertViewDelegate>//遵循登录监听协议LoginListener
{
//声明登录对象变量
UserLogin * _userLogin ;
}
@end
@implementation ViewPresenter
#pragma mark - 管理者的构造函数
- (instancetype)initWithMainView : (id<MainView>) mainView {
if (self = [super init]) {
_mainView = mainView ;//设置管理者的MainView
_userLogin = [[UserLogin alloc]init];
}
return self ;
}
#pragma mark - 控制器的登录事件
- (void) login {
[_mainView showProgress];
//登录
[_userLogin loginWithUserName:[_mainView getUserName] WithPassWord:[_mainView getPassWord] WithLoginListener:self];
}
#pragma mark - 登录监听 失败
- (void)Failure:(NSString *)errormessage {
[_mainView dismiss];
UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"登录失败" message:errormessage delegate:self cancelButtonTitle:@"知道了" otherButtonTitles: nil];
[alert show];
}
#pragma mark - 登录监听 成功
- (void)Sucess:(UserModel *)model {
[_mainView dismiss];
NSString *message = [NSString stringWithFormat:@"你的账号:%@ 登录成功",model.username];
UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"登录成功" message:message delegate:self cancelButtonTitle:@"知道了" otherButtonTitles: nil];
[alert show];
}
#pragma mark - 控制器的清空事件
- (void) clear {
[_mainView clearUserName];
[_mainView clearPassWord];
}
@end
以上业务逻辑层处理完毕,回到控制器中,声明管理者变量,实例化该变量,调用登录和清空事件遵循MainView协议,代码如下:
#import "ViewController.h"
#import "MainView.h"
@interface ViewController ()<MainView>//遵循View层的交互协议
{
__weak IBOutlet UITextField *userName;
__weak IBOutlet UITextField *passWord;
__weak IBOutlet UIActivityIndicatorView *activityBar;
//声明管理者变量
ViewPresenter *_presenter ;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
activityBar.hidden = true ;
//实例化管理者变量
_presenter = [[ViewPresenter alloc]initWithMainView:self];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)loginClick:(UIButton *)sender {
[_presenter login];//登录事件
}
- (IBAction)clearClick:(UIButton *)sender {
[_presenter clear];//清空事件
}
//=========== MainView 的协议实现 ===================
#pragma mark - 展示加载动画
- (void) showProgress {
activityBar.hidden = false ;
}
#pragma mark - 隐藏加载动画
- (void) dismiss {
activityBar.hidden = true ;
}
#pragma mark - 获得账号
- (NSString *) getUserName {
return userName.text ;
}
#pragma mark - 获得密码
- (NSString *) getPassWord {
return passWord.text ;
}
#pragma mark - 清空账号
- (void) clearUserName {
userName.text = @"" ;
}
#pragma mark - 清空密码
- (void) clearPassWord {
passWord.text = @"" ;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Demo的下载地址:
http://download.csdn.net/detail/flytosky_l/9755195
本文通过一个iOS OC的登录界面示例,详细解释了MVP模式在项目中的应用,旨在降低代码耦合度,增强可维护性。文中介绍了如何创建模型、视图、 presenter及业务逻辑层,以及各组件间的交互方式。
723

被折叠的 条评论
为什么被折叠?



