zoukankan      html  css  js  c++  java
  • 无线客户端框架设计(4):自定义生命周期的设计(iOS篇)

    首先要确定一点,我们的App,要基于XIB文件进行编程,而不是在每个相应的ViewController里面去手动创建页面的每个控件。这样做的好处是,将页面布局与业务逻辑彻底隔离。于是我们可以把xib的绘制工作交给美工人员,而iOS程序员,主要关心的是业务逻辑。

    有人会怀疑过多的xib会导致App体积变大,我曾经有专门看过ipa文件解压后的文件列表,我发现每个xib也就2k大小,而一个App最多也就七八十个xib,那么就是说共计150k大小的样子,由于是xml文本文件,所以压缩后更小。而相比较下,占用App体积最多的,往往是开机画面图,引导图这些东西,如果真的想要App瘦身,应该在图片上进行优化,而不是不使用xib直接布局。

    另一个需要明确的是,在一开始创建ViewController的时候,不要同时创建xib文件,因为这样子的话,就在xib中把ViewController和xib进行关联了,而我们要做的是解耦,这显然不合理。所以正确的流程是,分开创建ViewController和xib,不要进行管理。在ViewController的初始化中,加载xib文件,如下所示:

    接下来要做的事情,有时候连我都觉得匪夷所思。我们先来看一段代码:

     1 #import "APageViewController.h"
     2 
     3 @interface APageViewController ()
     4 
     5 @end
     6 
     7 @implementation APageViewController
     8 
     9 - (void)loadView
    10 {
    11     [super loadView];
    12     // Do any additional setup after loading the view.
    13 
    14     //1.从xib中获取View
    15     NSArray* list = [[NSBundle mainBundle] loadNibNamed: @"APageView" owner: self options: nil];
    16     self.view = list.lastObject;
    17     
    18     UILabel* nameLabel = (UILabel*)[self.view viewWithTag: 100];
    19     nameLabel.text = @"";
    20     
    21     UILabel* ageLabel = (UILabel*)[self.view viewWithTag: 200];
    22     ageLabel.text = @"";
    23     
    24     UIButton* getInfoButton = (UIButton*)[self.view viewWithTag: 300];
    25     [getInfoButton addTarget: self action: @selector(getInfo) forControlEvents:UIControlEventTouchUpInside];
    26     
    27     UIButton* clearInfoButton = (UIButton*)[self.view viewWithTag: 400];
    28     [clearInfoButton addTarget: self action: @selector(clearInfo) forControlEvents:UIControlEventTouchUpInside];
    29 }
    30 
    31 - (void) getInfo {
    32     UILabel* nameLabel = (UILabel*)[self.view viewWithTag: 100];
    33     nameLabel.text = @"包小强";
    34     
    35     UILabel* ageLabel = (UILabel*)[self.view viewWithTag: 200];
    36     ageLabel.text = @"31.6";
    37 }
    38 
    39 - (void) clearInfo {
    40     UILabel* nameLabel = (UILabel*)[self.view viewWithTag: 100];
    41     nameLabel.text = @"";
    42     
    43     UILabel* ageLabel = (UILabel*)[self.view viewWithTag: 200];
    44     ageLabel.text = @"";
    45 }
    46 
    47 - (void)dealloc {
    48     [super dealloc];
    49 }
    50 
    51 @end

     上面的代码,是再普通不过的一段代码,读取一个xib,获取到View的句柄,初始化其中的每个控件,为按钮挂上点击后的方法事件,使得按钮变红。内部还有个计数器变量,每次点击按钮都会加1。巧的是,恰好还要侦听一个通知(Notification)。最后,调用API。

    我们发现,有2个问题:

    1)在willDidLoad中做了太多的事情,又是初始化变量,又是初始化控件,又是给按钮挂事件,注册通知,还要调用API。

    2)每次使用控件时,都要根据在xib中指定的tag重新获取,而iOS中的控件tag值,只能是整数。

    我们的解决方案是,既然页面每次加载都会调用loadViewviewDidLoad方法,每次销毁都会调用dealloc方法,那么干脆就在基类BaseViewController重写了这几个方法,于是现在页面的生命周期如下所示:

    201309051002.jpg

    相应的基类代码请参见本章的源码。

     

    我们在每个页面都会重写createFieldsloadData这些方法,每个方法的意义如下:

    1createFieldsdestroyFields: 创建/销毁页面级变量的地方。

    2createViewsdestroyViews: 创建/销毁页面内控件的地方。

    3createEventsdestroyEvents: 创建/销毁页面内事件、通知的地方。

    4loadData: 如果页面加载过程需要调用MobileAPI,则写在这个地方。

     

    我们在程序里把代码分门别类写在各自的地方,易于管理(避免了经常会声明了变量而忘记销毁的问题)。

     

    于是刚才的代码文件,我们将其重构为: 

     1 #import "APageViewController.h"
     2 
     3 @interface APageViewController () {
     4     UILabel* nameLabel;
     5     UILabel* ageLabel;
     6     UIButton* getInfoButton;
     7     UIButton* clearInfoButton;
     8 }
     9 
    10 @end
    11 
    12 @implementation APageViewController
    13 
    14 - (void)createFields {
    15 
    16 }
    17 
    18 - (void)destroyFields {
    19     
    20 }
    21 
    22 - (void)createViews {
    23     //1.从xib中获取View
    24     NSArray* list = [[NSBundle mainBundle] loadNibNamed: @"APageView" owner: self options: nil];
    25     self.view = list.lastObject;
    26     
    27     nameLabel = (UILabel*)[self.view viewWithTag: 100];
    28     nameLabel.text = @"";
    29     
    30     ageLabel = (UILabel*)[self.view viewWithTag: 200];
    31     ageLabel.text = @"";
    32     
    33     getInfoButton = (UIButton*)[self.view viewWithTag: 300];    
    34     clearInfoButton = (UIButton*)[self.view viewWithTag: 400];
    35 }
    36 
    37 - (void)destroyViews {
    38     
    39 }
    40 
    41 - (void)createEvents {
    42     [getInfoButton addTarget: self action: @selector(getInfo) forControlEvents:UIControlEventTouchUpInside];
    43     [clearInfoButton addTarget: self action: @selector(clearInfo) forControlEvents:UIControlEventTouchUpInside];
    44     
    45 }
    46 
    47 - (void)destroyEvents {
    48     
    49 }
    50 
    51 - (void)loadData {
    52     //在这里调用API,对于多个API的调用,参加后续章节
    53 }
    54 
    55 - (void) getInfo {
    56     nameLabel.text = @"包小强";
    57     ageLabel.text = @"31.6";
    58 }
    59 
    60 - (void) clearInfo {
    61     nameLabel.text = @"";
    62     ageLabel.text = @"";
    63 }
    64 
    65 @end

    以上的代码重构,要遵守几个规则:

    1)在createFields方法中接收从上一个页面传递过来的参数

    2)在createFields方法中初始化变量

    3)将要操作的控件,都在ViewController中作为类级别的变量来声明

    3)在createViews方法中,加载xib文件,并通过Tag给控件一次性赋值

    4)在createEvent方法中,为控件挂上事件方法,比如按钮的点击

    5)如果有NotificationCenter,统一在createEvent方法中addObserver,在destroyEvent方法中removeObserver。

    6)在DestroyFields方法中,释放/销毁所有引用型变量。

    7)在DestroyViews方法中,释放/销毁所有控件。

     

    所有的ViewController都这么写,整个App整齐划一。尤其是将一个页面的所有控件一次性都从xib中根据tag值取出来,虽然浪费了一些内存,但是可以随时随地直接使用。

    将声明一个按钮和为按钮添加一个点击事件方案分开在2个方法内写,一开始你会非常不习惯,但是当控件多了、事件多了的时候,是一目了然的。记住,我们在做的是企业级App开发,而不是小型App。

     

    看到最后,熟悉网站端编程的人笑了,没错,这种新的生命周期,就是从javascript中借鉴来的。js是一门弱语言,所以需要自定义生命周期并按部就班在不同的方法中写不同的方法,生命周期的重新定义,或者说是扩展,只是js代码框架中的一个小部分。

     

    本章代码下载:

    YoungHeart-Chapter-04-1.zip (重构前)

    YoungHeart-Chapter-04-2.zip   (重构后)

     

  • 相关阅读:
    php socket 客户端代码
    linux crontab定时执行
    加载 pcntl 多进程
    Xdebug 配置
    Zend Debugger 配置
    windows SVN搭建
    深度学习笔记:优化方法总结(BGD,SGD,Momentum,AdaGrad,RMSProp,Adam)
    操作系统-分段机制
    C++中的new、operator new与placement new
    线程安全的概念
  • 原文地址:https://www.cnblogs.com/Jax/p/3302855.html
Copyright © 2011-2022 走看看