您的位置:首页 > 移动开发 > IOS开发

iOS项目重构周记(二)

2015-12-25 16:55 357 查看
iOS项目重构周记(二)

字数1214 阅读1184 评论12 喜欢16

继续上一篇,本周的重构重点是UI部分代码的优化。

AutoLayout及Masonry

AutoLayout是苹果在IOS6中推出的一种新的UI构建方式,旨在解决不同屏幕分辨率之间的适配问题。相信大多数人可能跟我一样,对这种方式是又爱又恨,因为AutoLayout中的确存在很多坑。不过随着iOS设备尺寸越来越多,还是值得去学习掌握AudoLayout的。

本次重构中在UITableViewCell中使用AutoLayout上遇到了一个坑,正常情况下在cell中使用AutoLayout需设置约束上下左右都为-8才能铺满整个Cell。但发现在iOS6中没有问题,但在iOS7以上,左右约束需设置为-15才能铺满。我的解决方案是在cell.contentView上再添加一层父View,针对不同的系统做了一个适配。但问题的根本原因目前还没有找到,有待后续观察。

另外,对于手写约束来说,使用苹果原生的API可能会很痛苦,因为约束代码将又臭又长,例如:

[self.view addConstraint: [NSLayoutConstraint constraintWithItem:AView

attribute:NSLayoutAttributeLeft

relatedBy:NSLayoutRelationEqual

toItem:BView

attribute:NSLayoutAttributeLeft

multiplier:1

constant:0]];

仅表示AView的左侧距离BView的左侧一个单位,所以有必要引入一些第三方工具。

Masonry是一个轻量级的布局框架 拥有自己的描述语法 采用更优雅的链式语法封装自动布局 简洁明了 并具有高可读性 而且同时支持 iOS 和 Max OS X。

上面那句使用Mansory可以精简为:

[AView mas_makeConstraints:^(MASConstraintMaker *make) {

make.left.equalTo(BView.left).with.offset(1);

}];

一个View的多个约束可以在同一个Block中实现,并且代码书写方式让人更容易理解。

更多使用技巧请戳:Masonry

Cell中对Layer的处理

其实cell中应避免一切对Layer的处理,包括圆角,阴影,甚至不应该包含任何透明View,因为这种渲染对系统的开销非常大,众多的Cell将使页面变的非常卡,在使用Layer时,也应该使用如下的方法减少以系统的开销。

self.layer.shouldRasterize = YES;

self.layer.rasterizationScale = [UIScreen mainScreen].scale;

CGPathRef path = [UIBezierPath bezierPathWithRect:self.bounds].CGPath;

[self.layer setShadowPath:path];

3. UITableViewCell中嵌套UITableView

看到网上有人说应该避免在UITableViewCell中使用UITableView,我觉得可以视需求的不同做不同的处理。对于一个模型结构非常复杂的TabeView,嵌套TableView可以降低代码的耦合,将不同的业务模型分散处理。只是需要注意的是,子TableView和父TableView的实现不应该在同一个文件中处理,也就是说delegate和dateSource不应该指向同一个对象,可以将子TableView封装成一个Cell,delegate和dataSource都交由这个Cell处理,这样才能有效降低代码的耦合,并且精简原文件的逻辑和大小。

UITableView中间层模型的封装

相信很多人会Cell的展示逻辑直接放到TableView的delegate中处理,例如:

(CGFloat)tableView:(UITableView )tableView heightForRowAtIndexPath:(NSIndexPath )indexPath

{

if (A) {

if(B){

return BHeight;

}

return AHeight;

}else if (C) {

if(B){

return BHeight;

}

return CHeight;

}

return 0;

}

(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

if(A){

if(B) {

return 2;

}

return 1;

}else if(C) {

if(B){

return 2;

}

return 1;

}

return 0;

}

(UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

if(A) {

if(B) {

return BCell;

}

return ACell;

}else if(C) {

if(B){

return BCell;

}

return CCell;

}

}

(void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath )indexPath

{

if(A) {

if(B) {

doB();

}

doA();

}else if(C) {

if(B){

doB();

}

doC();

}

}

所有代理中的逻辑都必须相同,而且同样的方法要写多次,例如上面的B。使用这样的方式,当遇到逻辑非常复杂的TableView时将使我们苦不堪言。TableView的代理应该只负责去构建Cell,而不应该来处理逻辑判断。所以,我们应该构建一个中间的模型层,在TableView reloadData的时候加载这个模型层,例如:

(void)setupTableModel

{

if(A) {

if(B) {

[arrayModel addObject:BModel];

}

[arrayModel addObject:AModel];

}else if(C) {

if(B){

[arrayModel addObject:BModel];

}

[arrayModel addObject:CModel];

}

}

(void)reloadTable

{

[self setupTableModel];

[tableView reloadData];

}

此时:

(CGFloat)tableView:(UITableView )tableView heightForRowAtIndexPath:(NSIndexPath )indexPath

{

if ([[array objectAtIndex:row] isEqual:AModel]) {

return AHeight;

}else if ([[array objectAtIndex:row] isEqual:BModel]) {

return BHeight;

}else if ([[array objectAtIndex:row] isEqual:CModel]) {

return CHeight;

}

return 0;

}

(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

return arrayModel.count;

}

(UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

if ([[array objectAtIndex:row] isEqual:AModel]) {

return ACell;

}else if ([[array objectAtIndex:row] isEqual:BModel]) {

return BCell;

}else if ([[array objectAtIndex:row] isEqual:CModel]) {

return CCell;

}

return nil;

}

(void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath )indexPath

{

if ([[array objectAtIndex:row] isEqual:AModel]) {

doA();

}else if ([[array objectAtIndex:row] isEqual:BModel]) {

doA();

}else if ([[array objectAtIndex:row] isEqual:CModel]) {

doA();

}

}

此时的delegate中只关注tableView的Cell构建和Cell行为,并不关心任何构建顺序等逻辑判断。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: