1. <fieldset id='gheob'></fieldset>

      <acronym id='gheob'><em id='gheob'></em><td id='gheob'><div id='gheob'></div></td></acronym><address id='gheob'><big id='gheob'><big id='gheob'></big><legend id='gheob'></legend></big></address>
      <span id='gheob'></span>
      <dl id='gheob'></dl>

        <code id='gheob'><strong id='gheob'></strong></code>
      1. <tr id='gheob'><strong id='gheob'></strong><small id='gheob'></small><button id='gheob'></button><li id='gheob'><noscript id='gheob'><big id='gheob'></big><dt id='gheob'></dt></noscript></li></tr><ol id='gheob'><table id='gheob'><blockquote id='gheob'><tbody id='gheob'></tbody></blockquote></table></ol><u id='gheob'></u><kbd id='gheob'><kbd id='gheob'></kbd></kbd>
      2. <i id='gheob'><div id='gheob'><ins id='gheob'></ins></div></i>

          <ins id='gheob'></ins>
          <i id='gheob'></i>

        1. iOS的MVC框架之控制层的构建(下)

          • 时间:
          • 浏览:10
          • 来源:124软件资讯网

            在我的iOS的MVC框架之控制层的构建(上)一文中先容了一些控制层的构建要领 ,而这篇文章则继续对一些要领举行睁开讨论  。MVC被众多开发者所诟病的C层的膨胀  ,究其缘故原由不外乎有如下几点:

            1. 所有视图的构建和结构代码都在控制器中完成  。有许多同砚不喜欢系统提供的Storyboard和XIB来构建视图  ,而是喜欢通过代码的形式来完成视图界面结构  ,而且通常这部门代码都集中在loadView或者viewDidLoad或者通过懒加载的形式疏散在各处  。通过代码来构建和结构视图的代码量有可能会凌驾您视图控制器总代码量的50% 。

            2. 对服务端的请求 ,往往就是包装了一层很是薄的请求层  ,通常称之为APIService 。 这部门代码只是简朴封装了对服务端URL的请求  ,同时通过一些报文转数据模子的第三方框架直接将报文转化为数据模子并通过异步回调的形式回吐给控制器或者视图  。APIService的简朴实现却增添了控制器的负荷  ,导致控制器除了要构建视图而且请求网络服务外还要担负很是多的一部门营业逻辑的实现 。

            3. 对于一些庞大展示逻辑的功效界面没有举行合理拆解和有用设计导致所有代码都在一个视图控制器内完成  ,从而导致控制器膨胀臃肿  。

            4. 在应用中最多使用的UITableView以及UITableViewCell中的数据更新的处置惩罚机制使用不适当导致delegate中的要领实现异常的庞大  ,尤其是那些庞大的UITableViewCell的更新处置惩罚不恰当导致代码杂乱不堪  。

            可以看出框架自己没有问题 ,问题在于使用的人不相识或者不适当的设计头脑导致问题泛起了  。当泛起问题时我们首先应该反思的是自己那里差池而不是去怪别人那里差池 。(这个鸡汤撒得真LOW!!) 怎么解决上面所说的导致C层膨胀的几个问题呢  ?这也是这篇文章所要重点先容的 。

            差别代码的构建时机

            控制器类是一个功效的调理总控室  ,而且他还通过模板要领的设计模式提供应了我们在控制器的生命周期内各阶段事务发生时的处置惩罚回调  。好比控制器构建时(init)、 视图构建时(loadView)、视图构建完成时(viewDidLoad)、视图将要出现到窗口前(viewWillAppear)、视图已经出现到窗口(viewDidAppear)、视图将要从窗口删除(viewWillDisappear)、视图已经从窗口删除(viewDidDisappear)、视图被销毁(viewDidUnload,这个要领在iOS6.0以后将不起作用了)、控制器被销毁(dealloc)  。为了实现功效  ,我们可能需要在上述的某个地方添加对应的处置惩罚代码 。怎样添加代码  ?以及在上述的模板要领中添加什么样的代码  ?就很是的要害了  。在这内里我想强调一点的是虽然控制器中拥有了一个view的根视图属性  ,可是控制器的生命周期一样平常要比根视图的生命周期要长 ,而且有可能会泛起一个功效在差别场景下的视图出现完全纷歧样  ,或者有可能会通过重新构建视图来实现一些换肤功效的场景  。在iOS6以后的控制器中只提供了视图构建以及构建完成的模板要领  ,但却不再提供视图被销毁之前或者之后的模板要领  ,因此我们在loadView以及viewDidLoad中添加代码时就一定要思量到这么一点  ,由于他不像其他的要领一样提供了互逆处置惩罚的机制  。

            • 控制器初始化(init)

              若是你的营业模子工具的生命周期和控制器的生命周期一样  ,那么建议将营业模子工具的构建放在控制器的初始化代码中  ,固然条件是你的营业模子工具是一个轻量级的工具  ,若是你的营业模子工具的构建特殊消耗时间那么不建议放在控制器的初始化中构建而是通过懒加载或者在某个触摸事务发生时再构建  。若是你的控制器由多个子控制器组成  ,那么子控制器的初始化事情也在这里完成最佳  。在控制器初始化时我们还可以初始化以及建立一些其他的轻量级的属性 ,这些属性或者变量的生命周期和控制器的生命周期一致 。

            • 视图构建(loadView)

              若是你的视图是通过SB或者XIB来建设的  ,那么恭喜你  ,你可以省略这部门代码  。若是你是通过代码来构建你的视图  ,那么你就有须要在这个地方添加你的视图构建和结构代码  。你需要重载loadView的要领  ,并在最幸亏这里完成所有视图的构建和结构  。若是你想复用默认的根视图作为自己的根视图那么你需要在构建你的其他子视图之前挪用基类的loadView要领  ,而若是你想要完全构建自己的根视图以及子视图系统那么你就不须要挪用基类的loadView要领  。许多人都喜欢在viewDidLoad内里举行视图的构建 ,实在不是最佳的解决方案 ,由于凭据字面意思viewDidLoad内里添加的应该是视图构建并加载完成后的一些处置惩罚逻辑  。怎样在loadView中越发优雅以及合理的结构界面结构代码 ,后面我将会给出一个详细解决方案  。

            -(void)loadView
            {
               /*
               自界说根视图的构建  ,不需要挪用基类的要领  。你也可以直接在这里将UIScrollView或者UITableView作为根视图  。
               这样就不必在默认的根视图上再建设转动视图或者列表子视图了  。
               */
                self.view = [[UIView alloc] initWithFrame: [UIScreen mainScreen].bounds];
            
               //...建设其他子视图  。
            
            }
            • 事务绑定的代码(viewDidLoad)

              当视图构建完毕后系统会挪用viewDidLoad 。因此您应该在这里完成一些营业逻辑初始化的行动、营业模子服务接口的初始请求、一些控件的事务处置惩罚绑定的行动、视图的delegate以及dataSource的设置  。也就是这里一样平常用来完成视图和控制器之间的关联处置惩罚以及控制器和营业模子的关联处置惩罚 。在viewDidLoad中最适合做的就是实现视图和控制器之间的绑定以及控制器和营业模子之间的绑定操作  。这里不建议举行视图的构建  ,以及一些涉及到整个控制器生命周期相关的处置惩罚  。

            • 视图的出现和消逝(viewWill/DidAppear,viewWill/DidDisappear)

              视图的出现和消逝有可能会被重复挪用  。建议在这里完成准时器、通知视察者的添加和销毁处置惩罚  。一样平常来说准时器和视察者都只是在界面被出现时发生作用  ,而界面消逝时则不处置惩罚 ,因此在这里添加准时器和通知视察者是最合适的 。而且另有一个利益就是在这里实现准时器和视察者时不会发生循环引用而导致控制器不能被释放的问题发生 。

            • 控制器被销毁(dealloc)

              控制器被销毁时讲明控制器的生命周期已经完结了 。一样平常情形下不需要添加特殊的代码  ,这里一再强调的就是:

            • 一定要在这里把种种控件视图中的delegate以及dataSource设置为nil!

            • 一定要在这里把种种控件视图中的delegate以及dataSource设置为nil!

            • 一定要在这里把种种控件视图中的delegate以及dataSource设置为nil!

            主要的事情说三遍  !不管这些delegate是assign照旧weak的 。

            懒加载

            懒加载的目的是为相识决按需建立使用以及可选使用以及耗时建立的场景  。在某种情形下使用懒加载可以加速展示的速率 ,懒加载可以将某些工具的建立时机延后  。那么是不是要将所有的工具的建立都接纳懒加载的形式举行建立  ? 谜底是否认的  。 有不少同砚都喜欢将控制器中的所有视图的建立和结构都通过懒加载的形式来完成  ,如下面的代码片断:

            @interface XXXViewController()
               @property(strong) UILabel *label;
               @property(strong) UITableView *tableView;
            @end
            
            @implementation XXXViewController
            
            -(UILabel*)label
            {
                 if (_label == nil)
                {
                      _label = [UILabel new];
                      [self.view addSubview:_label];
                     //有些同砚会在这里添加附加代码好比结构相关的代码
                }
                return _label;
            }
            
            -(UITableView*)tableView
            {
                 if (_tableView == nil)
                {
                       _tableView = [UITableView new];
                      [self.view addSubview:_tableView];
                      _tableView.delegate = self;
                     //有些同砚会在这里添加附加代码好比结构相关的代码
                }
                return _label;
            }
            
            
            -(void)viewDidLoad
            {
                [super viewDidLoad];
                self.label.text = @"hello";
                [self.tableView reloadData];
            }
            
            
            @end

            看起来代码很简练也很清晰  ,最少在viewDidLoad中是这样的  。可是这内里却有可能存在着一些隐患:

            • 视图条理顺序被打乱和代码疏散

              由于视图都是懒加载而且疏散的  ,因此你不能从整体看出视图条理结构是怎样的 ,以及排列的顺序是怎样的  。这就为我们的代码阅读以及调试和维护增添了难题 。

            • 职责不明确

              懒加载的主要作用是延迟建立 ,可是上述的视图属性的重写却已经超出了单纯的建立的领域了  ,除了建立视图之外还实现了视图添加到父视图的功效以及举行结构的功效  ,更有甚者另有可能实现其他越发庞大的逻辑 。这样就会导致一个get属性的实现承载的功效过多  ,严重的凌驾了一个要领所应负担的责任  。在使用时我们只是简朴的将其当做一个读取属性来使用而且另有可能发生有些代码重复的问题 。

            • 莫名的问题和瓦解

              懒加载视图使得我们的视图属性必须要设置为strong类型的  ,而且代码的实现是只建立一次  。若是由于某些缘故原由使得我们的控制器内里的所有视图都需要重新建立(好比换肤)时那么就有可能导致这个懒加载的视图不会再次被建立而发生界面上莫名其妙的问题  。更有甚者由于在懒加载中实现过多的代码导致在某些地方会见属性时发生了瓦解 。

            因此不建议对一个控制器内里的所有视图构建都接纳懒加载模式  ,视图的构建和结构应该在loadView中举行统一处置惩罚  。懒加载的方式不能滥用  ,尤其是视图的构建代码  。我们应该只对那些可选存在的工具以及那些有可能会影响性能的工具接纳懒加载的方式来举行构建  ,而不是所有的工具都接纳懒加载的形式来建立  。同时还需要注重的就是若是一定要接纳懒加载来实现工具的构建时  ,在懒加载中的代码也应该只管的简化  ,只需要实现建立部门的功效即可 ,而不要将一些非须要的逻辑代码放入到懒加载的实现处  ,越多的逻辑实现  ,就会对使用着发生越多的限制和不确定因素的发生 。就以上面的例子来说使用者在挪用self.label或者self.tableView时一样平常都只是将它们当做通俗的属性来使用  ,而不会去思量它们的内部还举行了云云多的设置和处置惩罚(好比完成结构和添加到父视图中去) 。这样就可能会造成对这些属性的使用不妥而造成灾难的结果 。另外虽然你的视图的构建是通过懒加载的形式来完成的  ,可是若是你在好比viewDidLoad中大量的会见这些属性时一样的会发生视图的构建操作  ,这样实在和直接建立视图工具是一样的  ,并没有起到任何优化性能的作用  ,而且这样也是和懒加载的初衷是违反的 。