C语言学习: iOS开发分分钟搞定C语言
OC语言学习: iOS开发核心语言Objective C
分享400G iOS学习资料。
获取途径:新浪微博 关注➕私信极客James
在 iOS 应用中日益增长的重量级视图控制器的问题。在典型的 MVC 应用里, 许多逻辑被放在 View Controller 里。
它们中的一些确实属于 View Controller,但更多的是所谓的“表示逻辑(presentation logic);
为了不让控制器日益增大,便于测试管理,便出现了MVVM.
MVVM:它其实是一个 MVC 的增强版,并将表示逻辑从 Controller 移出放到一个新的对象里,即 View Model
在 iOS 上使用 MVVM 的动机,就是让它能减少 View Controller 的复杂性并使得表示逻辑更易于测试.下面就通过一个小Demo来展示MVVM设计模式.
有关MVVM 设计模式的Demo
项目需求:
通过纯代码实现自定义不等高cell。
设计思路:
(1)创建项目,导入素材。
(2)创建数据模型
(3)创建视图模型
(4)在控制器中完成数据源及数据源方法
代码实现步骤
(1)创建项目,导入素材
(2)创建数据模型ZJStatus
在ZJSTatus.h中
@interface ZJStatus : NSObject
/*********显示数据模型********/
/** 头像 */
@property (nonatomic ,copy)NSString *icon;
/** 昵称 */
@property (nonatomic ,copy)NSString *name;
/** vip */
@property (nonatomic ,assign)BOOL vip;
/** 文字 */
@property (nonatomic ,copy)NSString *text;
/** 配图 */
@property (nonatomic ,copy)NSString *picture;
/*********显示frame模型********/
/** 头像 */
@property (nonatomic ,assign)CGRect iconFrame;
/** 昵称 */
@property (nonatomic ,assign)CGRect nameFrame;
/** vip */
@property (nonatomic ,assign)CGRect vipFrame;
/** 文字 */
@property (nonatomic ,assign)CGRect textframe;
/** 配图 */
@property (nonatomic ,assign)CGRect pictureFrame;
/** cell 的高度*/
@property (nonatomic,assign)CGFloat cellHeight;
在ZJSTatus.m中
#define KNameFont [UIFont systemFontOfSize:17] #define KTextFont [UIFont systemFontOfSize:14] @implementation ZJStatus // 重写cellHeight的get方法 - (CGFloat)cellHeight{ if (_cellHeight == 0) { // 设置边距为10 CGFloat margin = 10; // 设置cellHeight默认为0 CGFloat cellHeight = 0; // 1.头像 CGFloat iconX = margin; CGFloat iconY = margin; CGFloat iconW = 40; CGFloat iconH = iconW; self.iconFrame = CGRectMake(iconX, iconY, iconW, iconH); // 2.昵称 CGFloat nameX = CGRectGetMaxX(self.iconFrame) + margin; CGFloat nameY = iconY; // 昵称占据的宽度 NSDictionary *nameAttres = @{NSFontAttributeName :KNameFont}; CGSize nameSize = [self.name sizeWithAttributes:nameAttres]; // 通过结构体来存name的frame self.nameFrame = (CGRect){{nameX,nameY},nameSize}; // 3.vip if (self.vip) { CGFloat vipX = CGRectGetMaxX(self.nameFrame)+margin; CGFloat vipY = nameY; CGFloat vipW = 14; CGFloat vipH = nameSize.height; self.vipFrame = CGRectMake(vipX, vipY, vipW, vipH); } // 4.文字 TEXT CGFloat textY = CGRectGetMaxY(self.iconFrame) + margin ; CGFloat textX = iconX; CGFloat textW = [UIScreen mainScreen].bounds.size.width - 2*textX; // 4.1定义文字最大的显示尺寸 CGSize textMaxSize = CGSizeMake(textW, MAXFLOAT); // 4.2设置文字大小 NSDictionary *textAttr = @{NSFontAttributeName : KTextFont }; // 4.3设置文字的高度 CGFloat textH = [self.text boundingRectWithSize:textMaxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:textAttr context:nil].size.height; self.textframe = CGRectMake(textX, textY, textW, textH); // 5.配图 if (self.picture) { CGFloat pictureW = 100; CGFloat pictureH = pictureW; CGFloat pictureX = textX; CGFloat pictureY = CGRectGetMaxY(self.textframe) + margin; self.pictureFrame = CGRectMake(pictureX, pictureY, pictureW, pictureH ); // 如果有图 cell的高度为 _cellHeight = CGRectGetMaxY(self.pictureFrame); } else{ // 如果没有图 _cellHeight = CGRectGetMaxY(self.textframe); } // 让cellHeight 增加一个margin的高度 _cellHeight += margin; } return _cellHeight; }
(3)创建一个继承自UITableViewCell的视图模型ZJStatusCell
在ZJStatusCell.h中
@class ZJStatus;
@interface ZJStatusCell : UITableViewCell
/** status的数据 */
@property (nonatomic,strong) ZJStatus *status;
在ZJStatusCell.m中
#import "ZJStatus.h"
#define KNameFont [UIFont systemFontOfSize:17]
#define KTextFont [UIFont systemFontOfSize:14]
@interface ZJStatusCell ()
/** 头像 */
@property (nonatomic ,weak)UIImageView *iconImageView;
/** 昵称 */
@property (nonatomic ,weak)UILabel *nameLabel;
/** vip */
@property (nonatomic ,weak)UIImageView * vipImageView;
/** 文字 */
@property (nonatomic ,weak)UILabel *TEXTLabel;
/** 图片 */
@property (nonatomic ,weak)UIImageView *pictureImageView;
@end
@implementation ZJStatusCell
/** * 添加子控件(把有可能显示的子控件都加进去) */
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
// 1.昵称
UIImageView *iconImageView = [[UIImageView alloc]init];
[self.contentView addSubview:iconImageView];
// 连线 建立关系
self.iconImageView = iconImageView;
// 2.标题
UILabel *nameLabel = [[UILabel alloc]init];
[self.contentView addSubview:nameLabel];
self.nameLabel = nameLabel;
// 设置文字大小
self.nameLabel.font = KNameFont;
// 连线 建立关系
self.nameLabel = nameLabel;
// 3.vip
UIImageView *vipImageView = [[UIImageView alloc]init];
vipImageView.image = [UIImage imageNamed:@"vip"];
// 图片显示格式
vipImageView.contentMode = UIViewContentModeCenter;
[self.contentView addSubview:vipImageView];
// 连线 建立关系
self.vipImageView = vipImageView;
// 4.文字
UILabel *TEXTlabel = [[UILabel alloc]init];
[self.contentView addSubview:TEXTlabel];
self.TEXTLabel = TEXTlabel;
// 设置文字大小
self.TEXTLabel.font = KTextFont;
// 连线 建立关系
self.TEXTLabel = TEXTlabel;
// 换行
self.TEXTLabel.numberOfLines = 0;
// 设置一个背景颜色
// self.TEXTLabel.backgroundColor = [UIColor redColor];
// 5.配图
UIImageView *pictureImageView = [[UIImageView alloc]init];
[self.contentView addSubview:pictureImageView];
self.pictureImageView = pictureImageView;
// 连线 建立关系
self.pictureImageView = pictureImageView;
}
return self;
}
// 布局自控件
- (void)layoutSubviews{
#warning 一定要调用 [super layoutSubviews];
[super layoutSubviews];
// 直接从模型中调用相应的frame
// 头像
self.iconImageView.frame = self.status.iconFrame;
// 昵称
self.nameLabel.frame = self.status.nameFrame;
// vip
self.vipImageView.frame = self.status.vipFrame;
// 文字
self.TEXTLabel.frame = self.status.textframe;
// 图片
self.pictureImageView.frame = self.status.pictureFrame;
}
// 设置数据
- (void)setStatus:(ZJStatus *)status{
_status = status;
self.iconImageView.image = [UIImage imageNamed:status.icon];
self.nameLabel.text = status.name;
self.TEXTLabel.text = status.text;
// 图片
if (status.picture) {
self.pictureImageView.hidden = NO;
self.pictureImageView.image = [UIImage imageNamed:status.picture];
}
else {
self.pictureImageView.hidden = YES;
}
// vip 图标
if (status.vip) {
self.vipImageView.hidden = NO;
self.nameLabel.textColor = [UIColor orangeColor];
}else{
self.vipImageView.hidden = YES;
self.nameLabel.textColor = [UIColor blackColor];
}
}
(5)在控制器中
#import "ZJStatus.h"
#import "ZJStatusCell.h"
#import "MJExtension.h"
@interface ViewController ()
/** status的数组 */
@property (nonatomic,strong) NSArray *statuses;
@end
@implementation ViewController
- (NSArray *)statuses{
if (!_statuses) {
_statuses = [ZJStatus objectArrayWithFilename:@"statuses.plist"];
}
return _statuses;
}
NSString *ID = @"status";
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[ZJStatusCell class] forCellReuseIdentifier:ID];
// 设置cell 的高度为
//self.tableView.rowHeight = 250;
}
#pragma mark - 数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.statuses.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
ZJStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
cell.status = self.statuses[indexPath.row];
return cell
;
}
#pragma mark - 代理方法来算高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
ZJStatus *statue = self.statuses[indexPath.row];
return statue.cellHeight;
}
MVC与MVVM设计
上图展示了MVVM与MVC的差别。
在MVC模式的iOS开发中,Controller承担了太多的代码,包含着我们的视图处理逻辑和业务逻辑。
在MVVM中,我们将视图处理逻辑从C中剥离出来给V,剩下的业务逻辑部分被称做View-Model。
使用MVVM模式的iOS应用的可测试性要好于MVC,因为ViewModel中并不包含对View的更新,相比于MVC,减轻了Controller的负担,使功能划分更加合理。
MVVM模式的正确实践是,我们应该为app delegate的根视图创建一个ViewModel,当我们要生成或展示另一个次级ViewController时,采用当前的ViewModel为其创建一个子ViewModel。
而这些ViewModel的代码并不放在ViewController中,我们的View请求自己的ViewModel来获取所需的数据,ViewController完全归于View。