IOS (oc) 浅谈MVP在ios项目中的使用以及Demo
2017-02-14 19:10
435 查看
个人对于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
建立登录的数据模型(UserM
4000
odel):
在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 "ViewPresenter.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的理解:
登录界面:
首先创建一个空的项目,名为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
建立登录的数据模型(UserM
4000
odel):
在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 "ViewPresenter.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
相关文章推荐
- Android MVP 在项目中的使用 以及demo
- MVP浅谈,使用Swift语言完成登录界面的Demo
- ios之浅谈分类、类的扩展、协议以及协议的使用
- iOS 二维码的生成,以及自定义弹框Alert,使用及demo
- iOS开发:给项目工程里面添加Podfile配置文件,以及CocoaPods的简单使用
- OCLint-iOS-OC项目几种简单使用
- iOS开发:给项目工程里面添加Podfile配置文件,以及CocoaPods的简单使用
- iOS 整理基于socket集成Protobuf相关环境,以及将Protobuf文件转成OC文件,以及使用Protobuf
- 【iOS开发-94】xcode6怎么使用GIT以及如何给老得项目增加GIT功能?
- 如何在UINavigationBar上添加UISearchBar以及UISearchDisplayController的使用 --OC --iOS
- iOS开发小记:关于环信Demo3.0的使用总结以及昵称和头像问题的研究与解决
- 【iOS开展-94】xcode6如何使用GIT以及如何添加太老项目GIT特征?
- iOS开发——在 OC 项目中使用基于 Swift 的 CocoaPods 库
- 正确使用iOS常量(const)、enum以及宏(#define)在iOS开发中请尽量多使用const、enum来代替宏定义(#define);随着项目工程的逐渐增大,过多的宏定义还可能影响项目的编译
- 李洪强iOS开发之OC[002] - OC中注释以及@符号的使用
- iOS打包framework - Swift完整项目打包Framework,嵌入OC项目使用
- iOS开发OC基础:OC字典NSDictionary以及NSMutableDictionary基本方法的使用
- iOS开发OC基础:OC集合NSSet、NSMutableSet以及NSCountedSet的基本方法的使用
- TDD的iOS开发初步以及Kiwi使用入门
- xfire构建webservice项目步骤以及使用