认识View Controller

重复一万遍:基础很重要。。。。。

内容基本来自官方文档,确保可信。

@interface UIViewController : UIResponder <NSCoding, UIAppearanceContainer> {

@end

继承(Inherits from)UIResponder。

遵守(conform to)协议(protocol)NSCoding,UIAppearanceContainer和根对象NSObject。

属于UIkit.framework,iOS2.0及之后的版本支持该类。

作用概述(后面还会详细介绍View Controller的责任):

ViewController对内负责管理它的views,包括加载(load)和卸载(unLoad)等对资源的管理任务,另外,ViewController负责对事件进行处理(例如,应该知道该如何响应一个button的点击事件)。而对外的话,作为app的controller层的一部分,它专注于和模型对象(Model Objects)和其他的ViewController打交道。(这里的对内和对外不准确,但能够方便于我们去理解。而实际上,管理views也是对外的,因为遵循MVC的话,controller与view是松耦合的,views对于controller而言也是“外”,但从语义角度,因为controller管理view,所以认为是“对内”。)

在了解ViewController,先了解另外两个iOS中基础的两个类:Window和View,还有另外一个需要稍微知道的就是Screen。了解他们有助于了解ViewController。

UIScreen:表示设备的物理Screen。

UIWindow:提供在Screen上绘画(drawing)支持。

UIView:展现绘画的结果,附着到window上并在window的指示下绘制自己的内容。

与视图系统相关的类:

重点介绍views:

  1. view代表一个UI元素,占据一个区域,在此区域上展示自己的内容和响应用户事件。
  2. views是层级的,子view的位置布局和绘制与父view相关。例如,父view移动时,子view也是跟住移动的。
  3. views可以驱动(animate)它自己的属性值改变。多个属性值的改变可以实现一个单独的动画。
  4. views是知道自己在app中起什么作用的。例如一个button,它是一种特定的view,称为control。Controls知道怎么响应用户,但是他们不知道它们控制什么。取而代之的是,当一个用户与一个control交互时,它发送一个消息给其他的对象去处理。

使用view的时候,我们往往不需要assign一个view到window上,取而代之的是,我们assign一个ViewController到window上,然后ViewController会自动把views附着到window上。

先简单的了解controller对views的管理:

  1. 调整views大小(resize)和布局(lay out)views;

  2. 调整(ajust)views中的显示内容;

  3. 代表(on behalf of)views与用户交互。

ViewController的一些特性:

  • 一个view只能被一个ViewController控制。
  • ViewController与app的数据打交道。
  • 因为一个ViewController只能够提供有限的用户体验,所以要提供丰富的用户体验就需要多个ViewController之间联合起来。
 
 
ViewController之间的协作
 
ViewController之间的相互协作对应一个app的作用是相当重要的。这个也是ViewController的一个重要任务。
父与子关系:
这种关系表示的是包含关系。
 
ViewController的层次结构的有一个根节点,该根节点就是一个Window的ViewController。如果这个根节点是一个容器(Container),它可以包含子节点。下图以TabController作为一个例子:
 
 
 
根节点的区域受window制约,子节点受父节点制约。views和ViewControllers构成了app事件处理的响应链(responder chain)。
 
 
兄弟关系:
这种关系代表容器内的子节点的关联关系。
 
用Tab View Controller和Navigation Controller做一个比较:
 
  • Tabview Controller中,每一个tab展现的是不一样的内容,TabBar Controllers对它的子代没有定义关系。
  • 在navigation controller当中,子代的关系被关联到一个栈中,每一个子节点与临近节点是有项链关系的。
 
 
 
 
 
 
要将ViewController的内容起作用,就需要把ViewController展现在屏幕上,以下是几个展现它的几个方式:
  1. 将它作为window的根节点
  2. 将它作为一个可视的ViewController容器的子代
  3. 通过一个可视的ViewController展示(represent)它。
  4. 通过popover展示它(仅用于iPad)
谨记:千万不要把ViewController的view直接添加到view的层次结构中。为了展现和管理views,系统会把每一个展现的view以及它相关联的ViewController记下来。系统会使用这些信息去报告view controller-related(翻译?)事件。例如,当屏幕旋转时,window通过这个信息去 确定ViewController并且通知这一变化事件,如果你直接把ViewController的view添加到views的层次结构中,系统会错误地处理这事件。
 
 
创建自定义的Content View Controllers
 
 
自定义的Content View Controller基本是一个app的核心,每一个app至少需要有一个自定义的Content View Controller,复杂的app的工作基本都与这些Content View Controller有关。
 
 
Content View Controller分析
自定义的Content View Controller都实现了UIViewController,因为UIViewController提供了一些最基础的东西。自定义Content View Controller需要为views提供展现的数据和响应用户的操作。当你需要改变默认的行为时,只需要重写UIViewController中的响应方法就ok了。自定义Content View Controller也可以与其他的UIKit中的类协作,提供更多的行为方法。
 
 
 
上图中可以找出于Content View Controller相关的一些对象。其中,只有View是必须提供的(可以通过Content View Controller的view属性访问该对象)。当然,大部分Content View Controller的view会有子view,它也会有自定义的对象用户存储供展现的数据。
 
 
当你设计一个新的Content View Controller时,需要考虑它要负责的什么任务。对内,它管理views和一些它空控制的对象,对外,和别的controllers打交道,下面,我们介绍一个Content View Controller任务有那些。
 
 
 
Content View Controller的使命
 
 
1.管理资源
 
一些对象随controller初始化而出现,随controller释放而灭亡。一些对象,例如views,只有在view controller的内容展现在屏幕上才会被需要。正因此,view controller高效利用资源,并在资源紧缺时会释放资源。
 
谨记:view controller的view层次结构,只有在view被访问时才需要被初始化,大部分情况下,这种情况发生在它被展现到屏幕的时候。
 
当资源较少时,所有的view controller都会收到系统的通知,这个时候view controller就可以清除缓存和一些对象。
 
2.管理Views
 
view controller管理它的view以及下面的子view,但是这些view的frame(即view在它的父view中位置和大小)往往受到其他因素的影响,包括设备的方向,status bar是否显示,view controller是如果在window中展示的等。view controller应该保证布局它的view时能够适合提供给的frame。
 
另外,view controller当将要被展示在屏幕或者消息在屏幕时都会收到通知的所以view controller可以在这些时机做一些想做的操作。
 
3.响应事件
 
view controller是协调views和controls的最核心对象。当用户操作UI元素时,controls会发生消息给view controller,所以view controller要能够处理消息,改变views和数据。
 
view controller参与到响应链(responder chain)中传递事件。你可以直接重写方法去实现事件的处理。
 
4.和其他View Controllers合作
 
虽然view controllers往往会其他对象打交道,特别是其他的view controllers,但是view controllers应该尽可能少的暴露自己的属性和方法去其他协作者访问。暴露过多的话,会不方便于修改实现类。因为当你修改它的时候,协作者也需要修改相关细节。
 
5.经常和Containers一起工作
 
如果view controller被放置到一个view controllers容器(a container view controller)中,该容器会强加一些限制给view controller。例如,一个view controller被置于tab view controllers,那么就要提供tab bar item去展现tab。
 
 
6.可能通过其他的View Controllers展示出来
 
很多时候一个view controller的展示是通过其他view controller来实现的。
 
很多时候,你的app会为了收集或者展示一些信息,而弹出另外一个view controller暂时中断正常的workflow,大部分情况下,被弹出展现的view controller(presented view controller)实现了delegate。该view controller通过delegate去和展现它的那个view controller(presenting view controller)去实现交流。当app有了需要的信息后,被弹出的view controller就会把信息反馈给展现它的view controller。完成后,负责展现的view controller就会清除掉弹出的view controller,恢复到app之前的一个状态。
 
 
View Controller如何初始化View层次结构
 
当app访问一个view controller的view时,如果view没有在内存中,view controller就会加载它的view层次结构到内存中并且存储到它内部的成员变量view对象中,以便将来引用。具体流程是:
 
1.view controller调用loadView方法,loadView方法做两件事,一是,如果view controller关联storyboard,就从storyboard加载view,否则一个空的UIView对象被创建并被赋值到view属性中。
 
loadView方法一般做下面几件事:
  • 创建一个包含所有其他view的root view并与view controller关联。
  • 创建额外的子view添加到root view中。
  • 如果你使用自动布局(auto layout),要为view指定位置和大小限制。否则,要实现viewWillLayoutSubviews和viewDidLayoutSubViews去调整view层次中的这些子view的frame(位置和大小)
  • 将创建的root view赋值给view controller的view属性。
注意,loadView方法是不需要调用super的loadView的。调用的话会执行默认的加载view的操作和纯粹浪费cpu资源。
 
2.调用viewDidLoad方法,允许做一些额外的加载任务。
 
 
 
响应展现相关的通知
 
当一个view controller的view改变时,view controller会调用一些内建的方法去通知子views这些变化的发生。可以通过重写这些方法会响应这些变化。
 
响应view appear
 

响应View Disappear
 
 
响应链(Responder Chain)中的View Controllers
 
view controllers继承UIResponder,因此可以处理所有的事件。当一个view自己不响应事件时,它会传递给它的父亲,一直向上传递,直到root view。如果一个view是被view controllers管理的,那么它在把事件传递给父类之前先会传递给view controllers。因此,view controllers可以响应事件而不是view本身。
 
通过一个View Controller展现另外一个View Controller
 
通过展示一个view controllers,你可以打断当前的workflow,展示一系列的views。
 
像tab bar和navigation controller一样,当你希望传递出关于前一个view层和一个新展现view层的关系的这一特定意义时,你就可以展现一个view controller。
 
当你展现一个view controller时,系统就在当前展现的controller和被展现的controller之间创建了一个关系。展现的view controller通过更新它自己的presentedViewController属性指定被它展示的view controller。类似地,被展现的view controller通过更新自己的presentingViewController属性去指定展现它的那个view controller。
 
 
如何展现view controller和选择一个切换的风格
 
展现一个view controller的步骤:
1.创建这个view controller
2.设置view controller的modalTransitionStyle属性
3.赋一个delegate给这个view controller,一般情况下,这个delegate对象就是当前展现中的view controller。这个view controller将来会用这个delegate对象去通知当前被展现的这个view controller什么时候它会消失。同样,可以传递更多的一些信息给这个delegate对象。
4.调用当前view controller的presentViewController:animated:completion:方法,并传递希望展现的view controller对象。
 
 
Presentation Contexts提供view controller的展现区域
 
Presentation Context(后面简称PC)决定展示的区域。默认情况下,PC是由root view controller决定的,root view controller的frame决定了PC。然而,当前展现的view controller或者在view层次结构中的它的祖先,可以选择去提供PC。
 
当一个view controller被展现时,iOS会去查找一个presentation context。这个过程先从查看当前展现的view controller的definesPresentationContext开始,如果这个值为YES,那么这个值就被定义了,否则,一直沿view 层次结构网上找到YES为止,或者到达window的root view controller。
 
同样,除了view controller可以定义PC外,它还可以选择定义presentation style。
 
 
 
View Controllers之间的协作
 
view controller之间的协作,对应view controller的生命周期有三个阶段:
  1. view controller的初始化。在这一个阶段,一个已经存在的view controller负责创建一个新的view controller。有时候,已经存在的view controller会向新创建的view controller传递数据。有时候,会配置展现的方式和创建两者间持久的联系。这种联系保证了在view controller的声明周期当初可以相互交互。
  2. view controller的生命周期中。例如数据的传递等。
  3. view controller消亡。此阶段,很多view controller会在任务结束时发生消息。例如,把数据返回给一个view controller。
 
view controllers之间的协作很多时候都是使用delegate去实现的。delegate的好处是:
  • 通过delegate对象有机会去修改和合并数据。
  • 使用delegate能够提供良好的封装,view controller无需知道delegate的具体实现,以达到可重用。
 
创建自定义的Container View Controller
 
通常,一个container view controller和一个content view controller一样,管理views和内容,与其他controller协作,响应用户事件。
当你创建一个容器(container)时,你需要创建显式的父子关系。容器需要提供规则,子代就需要遵循这些规则。容器决定view的放置和在view层次结构中的位置、大小。
原文地址:https://www.cnblogs.com/chiefhsing/p/2943169.html