loadView / viewDidLoad / awakeFromNib / initWithCoder 总结


     每个 iOS 开发者对 loadView 和 viewDidLoad 肯定都很熟悉,虽然这两个函数使用上真的是非常简单,但是和类似的 initWithNibName: / awakeFromNib / initWithCoder: 放在一起还是非常容易让人混淆的。


一、loadView

      永远不要主动调用这个函数。view controller 会在 view 的 property 被请求并且当前 view 值为 nil 时调用这个函数。如果你手动创建 view,你应该重载这个函数, 且不要在重载的时候调用 [super loadview]。如果你用 IB 创建 view 并初始化 view controller,那就意味着你使用 initWithNibName:bundle: 方法,这时你不应该重载 loadView 函数。

       这个方法系统的默认实现是这样:

       1. 寻找有关可用的 nib 文件的信息,根据这个信息来加载 nib 文件       // 所以,nib 的加载过程是在 loadview 中完成的哦。

       2. 如果没有有关 nib 文件的信息,默认创建一个空白的 UIView 对象,然后把对象成赋值给 viewcontroller 的主 view。

      所以,如果你决定重载这个函数时,你也应该完成这些步骤:

      把子类的 view 赋给 view 属性(property)(你 create 的 view 必须是唯一的实例,并且不被其他任何 controller 共享),而且你重载的这个函数不应该调用 super,这个也是为了保持主 view 与 controller 的单一映射关系。


二、viewDidLoad

      这个函数在 controller 加载了相关的 views 后被调用,而不论这些 views 存储在 nib 文件里还是在 loadView 函数中生成。

      这个函数的作用主要是让你可以进一步的初始化你的 views。viewDidLoad 通常负责的是 view 及其子 view 被加载进内存之后的数据初始化的工作,即视图的数据部分的初始化。在 iOS 3.0 以及更高版本中,你应该重载 viewDidUnload 函数来释放任何对 view 的引用或者它里面的内容(子 view 等等)。

      其多数情况下是做 nib 文件的后续工作。


三、viewDidUnload

      iOS6 之前这个函数是 viewDidLoad 的对立函数。在程序内存欠缺时,这个函数被 controller 调用,来释放它的 view 以及 view 相关的对象。通常情况下,未显示在界面的 ViewController 是 UINavigationController Push 栈中未在栈顶的 ViewController,以及 UITabBarController 中未显示的子 ViewController。这些 ViewController 都在 MemoryWarning 事件发生时,让系统自动调用 viewDidUnload 方法。由于 controller 通常保存着 view 以及相关 object 的引用,所以你必须使用这个函数来放弃这些对象的所有权以便内存回收。但不要释放那些难以重建的数据。

      通常 controller 会保存 nib 文件建立的 views 的引用,但是也可能会保存着 loadView 函数创建的对象的引用。最完美的方法是使用合成器方法:

self.customSubview = nil;

      这样合成器会 release 这个 view,如果你没有使用 property,那么你得自己显式释放这个 view。


      但是 iOS6 之后,,由于viewDidUnload 事件任何情况下都不会被触发,所以苹果在文档中建议,应该将回收内存的相关操作移到另一个函数 didReceiveMemoryWarning 中。但是如果仅仅写成:(以下为错误示例)

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];


    if (self.isViewLoaded && !self.view.window) {
        self.view=nil;
    }
}


       在 iOS6 以后,不建议将 view 置为 nil 的原因如下:
       1. UIView 有一个 CALayer 成员变量,CALayer 用于将自己画到屏幕上:
       2. CALayer 是一个 bitmap 图像的容器类,当 UIView 调用自身的 drawRect 时,CALayer 才会创建 bitmap 图像类。
       3. 具体占内存的其实是一个 bitmap 图像类,CALayer 只占 48Bytes,UiView 只占 96Bytes。而一个 iPad 的全屏 UIView 的bitmap 类会占到 12MB 的大小。
       4. 在 iOS6,当系统发出 MemoryWarning 时,系统会自动回收 bitmap 类,但是不回收 UIView 和 CALayer 类。这样既能回收大部分内存,又能在需要 bitmap 类时,通过调用 UIView 的 drawRect: 方法重建。


       内存优化:
       苹果系统对上面的内存回收做了一个优化:
       1. 当一段内存被分配时,它会被标记成 “In Use”以防止被重复使用。当内存被释放时,这段内存被标记为 “Not in use”,这样有新的内存申请时,这块内存就可能被分配给其他变量。
       2. CALayer 包括的具体的 bitmap 内容的私有成员变量类型为 CABackingStore,当收到 MemoryWarning 时,CABackingStore 类型的内存会被标记为 Volatile 类型,表示这块内存可能再次被原变量使用。


       这样,有了上面优化后,当收到 MemoryWarning 时,虽然所有的 CALayer 所包含的 bitmap 内存被标记成 volatile 了,但是只要这块内存没有被复用,当需要重建 bitmap 内存时,可以直接被复用,避免了再次调用 UIView 的 drawRect:方法。
       简单说:iOS6 之后,不需要做任何以前 viewDidUnload 的事情,更不需要把以前 viewDidUnload 的代码移到didReceiveMemoryWarning 方法中。


四、initWithCoder:

      当使用了 IB 创建对象,并实例化的时候会调用。

      使用 IB 创建对象,其实就是写了 xib 或者 sb 文件(XML文件),那么反序列化的工作是由系统完成的。


五、awakeFromNib

      IB 创建的对象被实例化的时候调用。

      当 initWithCoder: 被调用之后,也会调用 awakeFromNib。但是 awakeFromNib 相对于 initWithCoder: 有个优势,后者在调用时虽然 subViews 已经被添加到图层中去了,但是还没有引用。而在 awakeFromNib 调用时,各种 IBOutlet 也都连接好了。


六、结论

      所以流程应该是这样:

      loadView 来加载 view (无论nib文件或自定义的views)到内存 ——> viewDidLoad 函数进一步初始化这些view (通常是侧重于数据 data 的初始化) ——> 内存不足时,调用 viewDidUnload 函数释放 views ——> 当需要使用 view 时又回到第一步,如此循环

      需要理清两个概念,创建一个类和实例化一个类。在 Xcode 中创建一个类和实例化一个类很容易区分,但是在 IB(Interface Builder) 中有时候就会迷糊。其实也很好区分,孤零零地创建了一个nib文件,没有和其他可被实例化的类有直接或间接关系的时候,这个类或这些类(一个 nib 文件也可能包含多个类)是没有机会被实例化的,所以这种情况只是通过 IB 创建了一个类,而没有实例化。真正的实例化还需要通过在 Xcode 用代码来读取这个 nib 文件。知道这两者的区别后这些方法也就容易辨认多了。

      loadView 需要分两种情况。当你通过 Xcode 实例化一个类的时候就需要自己在 controller 中实现这个方法。而在 IB 中实例化就不需要实现它。

      viewDidLoad 其实没什么可混淆的,无论通过什么途径加载(Xcode 或者 IB,这里的加载属于实例化)完 view 对象到内存后肯定会执行这个方法。

      initWithNibName: 这个方法是在 controller 的类在 IB 中创建,但是通过 Xcode 实例化 controller 的时候用的。

      initWithCoder 是一个类在 IB 中创建但在 Xcode 中被实例化时被调用的。比如,通过 IB 创建一个 controller 的 nib 文件,然后在 Xcode 中通过 initWithNibName 来实例化这个 controller,那么这个 controller 的 initWithCoder 会被调用。

      awakeFromNib 当 .nib 文件被加载的时候,会发送一个 awakeFromNib 的消息到 .nib 文件中的每个对象,每个对象都可以定义自己的 awakeFromNib 函数来响应这个消息,执行一些必要的操作。也就是说通过 nib 文件创建 view 对象时执行 awakeFromNib。awakeFromNib 在 loadView 前被调用。


七、补充

      在 IB 上创建类和实例化类的区分。IB 上实例化需要 Xcode 通过代码来读取这个 nib 文件的时候才会实例化。所以有些时候,我们创建了一个 xib 文件,里面有些控件,比如 UIButton,在没有被显示之前,这个 UIButton 可能只是一个 nil 指针。所以可以在viewWillAppear: 里对这些控件属性进行设置。
      当使用一个 controller 控制多个 nib 文件时,awakeFromNib 方法会被多次调用。因此,当不使用 awakeFromNib 方法来完成 nib 对象的初始化时,需要注意此方法的多次调用对其他 nib 文件造成的影响。


八、苹果接口文档

 

- (void)loadView

Description Creates the view that the controller manages.

You should never call this method directly. The view controller calls this method when its view property is requested but is currently nil. This method loads or creates a view and assigns it to the view property.

If the view controller has an associated nib file, this method loads the view from the nib file. A view controller has an associated nib file if the nibName property returns a non-nil value, which occurs if the view controller was instantiated from a storyboard, if you explicitly assigned it a nib file using the initWithNibName:bundle: method, or if iOS finds a nib file in the app bundle with a name based on the view controller'€™s class name. If the view controller does not have an associated nib file, this method creates a plain UIView object instead.

If you use Interface Builder to create your views and initialize the view controller, you must not override this method.

You can override this method in order to create your views manually. If you choose to do so, assign the root view of your view hierarchy to the view property. The views you create should be unique instances and should not be shared with any other view controller object. Your custom implementation of this method should not call super.

If you want to perform any additional initialization of your views, do so in the viewDidLoad method.

 

 

- (void)viewDidLoad

Description Called after the controller'€™s view is loaded into memory.

This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView method. You usually override this method to perform additional initialization on views that were loaded from nib files.

 


- (void)awakeFromNib

Description Prepares the receiver for service after it has been loaded from an Interface Builder archive, or nib file.

The nib-loading infrastructure sends an awakeFromNib message to each object recreated from a nib archive, but only after all the objects in the archive have been loaded and initialized. When an object receives an awakeFromNib message, it is guaranteed to have all its outlet and action connections already established.

You must call the super implementation of awakeFromNib to give parent classes the opportunity to perform any additional initialization they require. Although the default implementation of this method does nothing, many UIKit classes provide non-empty implementations. You may call the super implementation at any point during your own awakeFromNib method.

Note:Note

During Interface Builder’s test mode, this message is also sent to objects instantiated from loaded Interface Builder plug-ins. Because plug-ins link against the framework containing the object definition code, Interface Builder is able to call their awakeFromNib method when present. The same is not true for custom objects that you create for your Xcode projects. Interface Builder knows only about the defined outlets and actions of those objects; it does not have access to the actual code for them.

During the instantiation process, each object in the archive is unarchived and then initialized with the method befitting its type. Objects that conform to the NSCoding protocol (including all subclasses of UIView and UIViewController) are initialized using their initWithCoder: method. All objects that do not conform to the NSCoding protocol are initialized using their init method. After all objects have been instantiated and initialized, the nib-loading code reestablishes the outlet and action connections for all of those objects. It then calls the awakeFromNib method of the objects. For more detailed information about the steps followed during the nib-loading process, see Nib Files in Resource Programming Guide.

Important:Important

Because the order in which objects are instantiated from an archive is not guaranteed, your initialization methods should not send messages to other objects in the hierarchy. Messages to other objects can be sent safely from within an awakeFromNib method.

Typically, you implement awakeFromNib for objects that require additional set up that cannot be done at design time. For example, you might use this method to customize the default configuration of any controls to match user preferences or the values in other controls. You might also use it to restore individual controls to some previous state of your application.






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值