IOS 开发模式 之MVC模式
说到MVC 模式,根据意思来说 Model ,View,Controller 模型,视图,控制。
说是这么说,但是还是不明白到底应该怎么弄。(这其实是说我自己的,从下面就能看出)。
Model 模型,建立一个数据模型,里面是我们需要用到的数据,可以建立多个模型,一个模型里面包含另一个模型。
View 视图,创建视图。把需要用到的控件视图,建立一个子类。在里面设置视图,最后返回出来,代理一般在自己界面中是实现,一般就是自己创建的子类中实现。有时候还可以对model 的数据操作
Controller 控制器。 里面就是一些逻辑的处理 ,把返回的View 视图添加到界面上,删除控件等逻辑的是实现,对Model 数据的操作。
(我目前是这样理解的,根据MVC的定义,View只需要处理视图,对数据Model 的处理 应该在Controller 中,我目前在View 处理数据,以后再根据理解慢慢更改)
下面粘贴一段 网上复制过来的其他网友的话:
在iOS cocoa touch 编程中, MVC机制被发挥得淋漓尽致。 MVC 示意图如下。 只有充分理解了MVC,才能在编写出优雅的iOS app。为充分理解 MVC, 相关的概念(比如: Delegate、 Protocol、 Notification 等)也要了然于胸。
MVC 约定, Model 不允许与View 打交道。 Model 是管理数据的, 当Model中的数据发生变化时,与之对应的视图应更新。 这就需要一种机制来支持。为此 iOS 框架提供了两种支持机制: Notification 和KVO (Key-Value Observing)。
KVO 可简单理解为,为你所关注的 Key 对象注册一个监听器。 当有数据发生变化时,就会发出广播给所有的监听器。
MVC 也约定, View 不允许直接引用Modal, 它只能被Controller 所控制。 Controller 控制 View 显示什么数据。我们知道,View 所要显示的数据是来源于 Modal, View 上产生的事件 ( 比如 Touch事件)需要通知 Controller。 既然MVC 不允许直接打交道,就需要提供一种机制。
不错, iOS 确实提供了一种机制, 名曰: Delegate。 Delegate 这个词, 有人将它译为“委托”,也有人将它译为“代理”。名称上的差异没有什么,重要的是如何理解 Delegate。 Delegate设计模式的引入,就是为了解决UIView与Controller松耦合互动问题。
下面的代码 有我自己写的 还有参考其他大神的
定义的Model
SectionModel
#import <Foundation/Foundation.h>
//分区模型
@interface SectionModel : NSObject
@property (nonatomic, copy) NSString *sectionTitle;
//是否可以展开
@property (nonatomic, assign) BOOL isExpanded;
//分区下面可以有很多个cell对应的模型
@property (nonatomic, strong) NSMutableArray *cellModels;
@end
CellModel
#import <Foundation/Foundation.h>
@interface CellModel : NSObject
@property (nonatomic, copy) NSString *title;
@end
创建View
我自定义了一个TableView 并在里面对数据进行 处理,但是这样不符合MVC模式 我只是根据自己理解这样设置的
#import <UIKit/UIKit.h>
@interface TableView : UITableView
-(instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style;
@end
TableView 的实现文件 我导入了Model 模型文件
#import "TableView.h"
#import "HeaderView.h"
#import "SectionModel.h"
#import "CellModel.h"
@interface TableView ()<UITableViewDelegate,UITableViewDataSource,UIAlertViewDelegate>
@property (nonatomic,strong) NSMutableArray *dataArray;
@end
@implementation TableView
-(NSMutableArray *)dataArray
{
if (_dataArray == nil) {
_dataArray = [[NSMutableArray alloc]init];
for (NSInteger i = 0; i < 3; i++) {
//设置分区
SectionModel *sectionModel = [[SectionModel alloc]init];
sectionModel.isExpanded = NO;
sectionModel.sectionTitle = [NSString stringWithFormat:@"section = %ld",i];
//设置cell
NSMutableArray *array = [[NSMutableArray alloc]init];
for (NSInteger j = 0; j < 5; j++) {
CellModel *cellModel = [[CellModel alloc]init];
cellModel.cellTitle = [NSString stringWithFormat:@"section = %ld, row = %ld",i,j];
cellModel.webImageUrl = [NSString stringWithFormat:@""];
[array addObject:cellModel];
}
sectionModel.cellModels = array; //分区模型里面添加cell模型
[_dataArray addObject:sectionModel]; //数据里面添加分区模型
}
}
return _dataArray;
}
-(instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{
if (self = [super initWithFrame:frame style:style]) {
self.delegate = self;
self.dataSource = self;
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;
[self registerClass:[HeaderView class] forHeaderFooterViewReuseIdentifier:headerIdentifier];
}
return self;
}
#pragma mark UITableViewDataSource
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.dataArray.count;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
SectionModel *sectionMocel = self.dataArray[section];
return sectionMocel.isExpanded ? sectionMocel.cellModels.count : 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"TableView";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
UIView *selectBg = [[UIView alloc]initWithFrame:cell.frame];
selectBg.backgroundColor = [UIColor redColor];
cell.selectedBackgroundView = selectBg;
cell.backgroundColor = [UIColor grayColor];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
SectionModel *sectionModel = self.dataArray[indexPath.section];
CellModel *cellModel = sectionModel.cellModels[indexPath.row];
cell.textLabel.text = cellModel.cellTitle;
return cell;
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
#pragma mark UITableViewDelegate
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return headerHeight;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
HeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerIdentifier];
SectionModel *sectionModle = self.dataArray[section];
headerView.model = sectionModle;
headerView.expandCallBack = ^(BOOL isExpanded){
[tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
};
return headerView;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
SectionModel *sectionModel = self.dataArray[indexPath.section];
CellModel *cellModel = sectionModel.cellModels[indexPath.row];
NSLog(@"点击到的是%@",cellModel.cellTitle);
[self alert:sectionModel.sectionTitle message:cellModel.cellTitle];
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete){
SectionModel *sectionModel = self.dataArray[indexPath.section];
[sectionModel.cellModels removeObjectAtIndex:indexPath.row];
NSLog(@"删除");
}
[tableView reloadData];
}
-(void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"结束编辑");
}
-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
return @"点击删除";
}
-(void)alert:(NSString *)title message:(NSString *)messsage
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:title message:messsage delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
[alert show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
//确定 为1 取消 为0
switch (buttonIndex) {
case 0:
NSLog(@"0");
break;
case 1:
NSLog(@"1");
break;
default:
break;
}
}
Controller
Controller 文件 里面就比较简单了
#import "TableView.h" //导入子类文件
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tableView = [[TableView alloc]initWithFrame:CGRectMake(0, 100, View_Width, 300) style:UITableViewStylePlain];
[self.view addSubview:tableView];
}
我自定义表头
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
@class SectionModel;
FOUNDATION_EXPORT NSString *headerIdentifier;
FOUNDATION_EXPORT CGFloat headerHeight;
typedef void(^HeaderViewExpandCallBack)(BOOL isExpanded);
@interface HeaderView : UITableViewHeaderFooterView
@property (nonatomic,strong) SectionModel *model;
@property (nonatomic,copy) HeaderViewExpandCallBack expandCallBack;
-(instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier;
@end
表头文件的是实现
#import "HeaderView.h"
#import "SectionModel.h"
NSString *headerIdentifier = @"headerIdentifier";
CGFloat headerHeight = 44;
@interface HeaderView ()
@property (nonatomic,strong) UIImageView *arrowImageView;
@property (nonatomic,strong) UILabel *titleLabel;
@end
@implementation HeaderView
-(instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithReuseIdentifier:reuseIdentifier]) {
CGFloat width = [UIScreen mainScreen].bounds.size.width;
self.arrowImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"back1.png"]];
self.arrowImageView.frame = CGRectMake(0, (44-8)/2, 15, 8);
[self.contentView addSubview:self.arrowImageView];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(onExpand:) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:button];
button.frame = CGRectMake(0, 0, width, 44);
self.titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(35, 0, 200, 44)];
self.titleLabel.textColor = [UIColor blackColor];
self.titleLabel.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:self.titleLabel];
self.contentView.backgroundColor = [UIColor greenColor];
UIView *line = [[UIView alloc]initWithFrame:CGRectMake(0, 43, width, 1)];
line.backgroundColor = [UIColor lightGrayColor];
[self.contentView addSubview:line];
}
return self;
}
//我们在配置数据的时候,也会根据isExpanded状态来显示图片的方向,否则重用后就恢复原状了。
-(void)onExpand:(UIButton *)sender
{
self.model.isExpanded = !self.model.isExpanded;
[UIView animateWithDuration:0.25 animations:^{
if (self.model.isExpanded) {
self.arrowImageView.transform = CGAffineTransformIdentity;
}else{
self.arrowImageView.transform = CGAffineTransformMakeRotation(M_PI);
}
}];
if (self.expandCallBack) {
self.expandCallBack(self.model.isExpanded);
}
}
//重写setModel方法来配置数据 get 只读 set 设置
-(void)setModel:(SectionModel *)model
{
if (_model != model) {
_model = model;
}
if (model.isExpanded) {
self.arrowImageView.transform = CGAffineTransformIdentity;
}else{
self.arrowImageView.transform = CGAffineTransformMakeRotation(M_PI);
}
self.titleLabel.text = model.sectionTitle;
}
@end