对于MVC,个人更喜欢叫做架构模式,因为MVC和我们在进行iOS开发使用的代理、单例等设计模式是有很大的区别的。
近日看到一些使用MVC架构模式的代码,发现一些同学可能不是很理解MVC架构模式,因为有很多人很可能认为自己使用了MVC架构,但是仅仅是一种表象而已。例如近日接管代码时,看到以往的同学在写代码时,虽然设置了model、view和controller,但是model中仅仅定义了几个属性而无其他操作,view中只是定义了几个子控件也没有其他的操作,大部分以及全部的数据处理逻辑和业务逻辑等都还是放在controller中,显而易见,这不是规范的MVC架构模式。
正常的MVC架构模式:
模型对象:包含了需要使用的数据,以及处理这些数据的业务逻辑和运算方式。
视图对象:展示模型对象数据的视图,只做可视效果上的更改和展示。
控制器对象:因为模型对象和视图对象是相互独立的,所以需要使用控制器对象来充当模型对象和视图对象之间的媒介。
以上说的比较简洁,通过代码直观得来讲解一下:首先我写了一个根据内容动态计算单元格高度的界面。
效果展示:
工程目录:
下面是我的controller中的内容(其中附带讲解):
#import "ViewController.h"
#import "TableViewCell.h"
#import "DataModel.h"
static NSString *iden = @"唯一标识";
@interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
/** 存放数据的数组 */
@property (nonatomic, strong) NSMutableArray *dataArray;
@end
@implementation ViewController
#pragma mark - 懒加载
-(NSMutableArray *)dataArray{
if (_dataArray == nil){
//加载本地的数据
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"source.plist" ofType:nil];
NSArray *array = [NSArray arrayWithContentsOfFile:filePath];
_dataArray = [NSMutableArray array];
for (NSDictionary *dic in array) {
DataModel *model = [DataModel configDataModelWithDictionary:dic];
[_dataArray addObject:model];
}
}
return _dataArray;
}
#pragma mark - 控制器声明周期
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tableView.dataSource = self;
tableView.delegate = self;
tableView.separatorColor = [UIColor clearColor];
[self.view addSubview:tableView];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:iden];
if (cell == nil){
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:iden];
}
/**
将model的数据传递给cell,其中包含 1>需要展示的文本内容 2>cell中子控件的frame数据
*/
cell.model = self.dataArray[indexPath.row];
return cell;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
/**
单元格的高度属于数据,应包含在model中的,所以在返回高度的代理方法中,直接返回model中的高度数据
在model中进行高度计算的时候,我们同时进行其他的数据计算(例如名言警句的标签的高度的计算)
*/
DataModel *dataModel = self.dataArray[indexPath.row];
return dataModel.cellHeight;
}
@end
model中的代码:
DataModel.h:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface DataModel : NSObject
//根据数据源建立model
+ (instancetype) configDataModelWithDictionary:(NSDictionary *)dictionary;
/** 单元格的高度 */
@property (nonatomic, assign) CGFloat cellHeight;
/** 电影名字 */
@property (nonatomic, strong) NSString *name;
/** 精选的句子 */
@property (nonatomic, strong) NSString *content;
/** 电影名字标签的frame */
@property (nonatomic, assign) CGRect nameLabelFrame;
/** 精选句子的便签的frame */
@property (nonatomic, assign) CGRect contentLabelFrame;
@end
DataModel.m:
#import "DataModel.h"
#define KWidth [UIScreen mainScreen].bounds.size.width
#define KHeight [UIScreen mainScreen].bounds.size.height
#define space 20
@implementation DataModel
+ (instancetype) configDataModelWithDictionary:(NSDictionary *)dictionary{
DataModel *model = [[self alloc] init];
model.name = dictionary[@"name"];
model.content = dictionary[@"text"];
return model;
}
- (CGFloat)cellHeight{
if (_cellHeight == 0){
//名字标签的frame
_nameLabelFrame = CGRectMake(space, space, KWidth-space*2, space*2);
//句子标签的frame
//根据内容动态设置高度
CGSize contentLabelMaxSize = CGSizeMake(KWidth-space*2,MAXFLOAT);
// 计算文字的高度
CGFloat contentLabelHeight = [self.content boundingRectWithSize:contentLabelMaxSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:20]}
context:nil].size.height;
_contentLabelFrame = CGRectMake(space, space*4, KWidth-space*2, contentLabelHeight);
//单元格的高度
_cellHeight = space*5+contentLabelHeight;
}
return _cellHeight;
}
@end
View中的代码:
TableViewCell.h:
#import <UIKit/UIKit.h>
@class DataModel;
@interface TableViewCell : UITableViewCell
/** 模型数据 */
@property (nonatomic, strong) DataModel *model;
@end
TableViewCell.m:
#import "TableViewCell.h"
#import "DataModel.h"
@interface TableViewCell ()
/** 电影名称标签 */
@property (nonatomic, strong) UILabel *nameLabel;
/** 精选的句子标签 */
@property (nonatomic, strong) UILabel *contentLabel;
/** 分割线 */
@property (nonatomic, strong) UIView *operationView;
@end
@implementation TableViewCell
//初始化方法中添加需要的子控件
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
/** 电影名称标签 */
self.nameLabel = [[UILabel alloc] init];
self.nameLabel.font = [UIFont systemFontOfSize:17];
self.nameLabel.backgroundColor = [UIColor lightGrayColor];
[self.contentView addSubview:self.nameLabel];
/** 精选的句子标签 */
self.contentLabel = [[UILabel alloc] init];
self.contentLabel.font = [UIFont systemFontOfSize:20];
self.contentLabel.backgroundColor = [UIColor brownColor];
self.contentLabel.numberOfLines = 0;
[self.contentView addSubview:self.contentLabel];
//添加分割线
self.operationView = [[UIView alloc] init];
self.operationView.backgroundColor = [UIColor blackColor];
self.operationView.alpha = 0.8;
[self.contentView addSubview:self.operationView];
//取消点击的效果
self.selectionStyle = UITableViewCellSelectionStyleNone;
}
return self;
}
//布局子控件的时候设置子控件的frame
- (void)layoutSubviews{
_nameLabel.frame = self.model.nameLabelFrame;
_contentLabel.frame = self.model.contentLabelFrame;
_operationView.frame = CGRectMake(0, CGRectGetHeight(self.contentView.frame)-1, [UIScreen mainScreen].bounds.size.width, 1);
}
//cell的model的setter方法,进行数据的赋值
- (void)setModel:(DataModel *)model{
_model = model;
_nameLabel.text = model.name;
_contentLabel.text = model.content;
}
@end
代码下载地址:http://download.csdn.net/detail/wuzesong/9697013