iOS项目重构周记(二)

iOS项目重构周记(二)
字数1214 阅读1184 评论12 喜欢16
继续上一篇,本周的重构重点是UI部分代码的优化。

  1. 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

  1. 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处理,这样才能有效降低代码的耦合,并且精简原文件的逻辑和大小。

  1. 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行为,并不关心任何构建顺序等逻辑判断。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值