iOS Programming - 第五章 视图控制器

iOS Programming - 第五章 视图控制器


视图控制器是 UIViewController 的子类的一个实例。 视图控制器管理着视图层级。它负责创建组成视图层级的视图对象并在视图层级中处理跟视图对象关联的事件。

视图控制器中的 View


作为 UIViewController 的子类, 所有的视图控制器都继承了一个重要的属性:

var view: UIView!

这个属性指向一个 UIView 实例, 这个 view 是视图控制器的视图层级中的根视图。当视图控制器的 view 被作为 window 的子视图添加时, 该视图控制器的整个视图层级就被添加上了。

img
img

视图控制器的 view 直到它需要出现在屏幕上时才被创建。这种优化叫做懒加载(lazy loading), 这能减少内存使用并提升性能。

视图控制器有两种方式创建它的视图层级:

  • 编写程序, 通过重写 UIViewControllerloadView 方法
  • Interface Builder 中, 通过使用诸如 storyboard 的界面文件

在第三章中你已经使用了这两种方法, 在第六章中你将使用 loadView() 创建程序上的视图。

设置初始的视图控制器


每个 storyboard 都可以有很多视图控制器, 但是每个 storyboard 文件只有一个初始视图控制器(initial view controller)。 初始视图控制器是 storyboard 的入口点。你将在画布中添加并配置另外一个视图控制器并把该控制器设置为 storyboard 的初始视图控制器。

打开 Main.storyboard, 从对象库中, 拖拽一个 ViewController 到画布中, 如果你用完了可用的空间, 你可以按住 Ctrl 并单击背景视图来选择不同的缩放比例。

img

用这个视图控制器来显示 MKMapView。先选中这个 View Controllerview, 而不是 View Controller 自身! — 并按下 Delete 键来从画布中删除这个 view。 然后从对象库中拖拽一个 Map Kit View 到这个视图控制器中以把它设置为该视图控制器的 view

img

选中 View Controller 并打开它的属性检查器。勾选 Initial View Controller , 则该视图控制器的前面会出现一个灰色的箭头。

MKMapView 是一个当前未被加载到程序中的框架。框架是一个共享代码库, 里面包含诸如界面文件和图片等关联的资源。

现在你需要导入 MapKit 框架以加载 MKMapView。使用 import 关键字但不使用包含任何使用该框架的代码来导入 MapKit 会导致编译器把它优化掉 — 即使你在 storyboard 中使用 map view。

相反, 你需要手动地把 MapKit 链接到 app 中。

打开工程导航, 点击工程名。在设置中打开 General 标签, 滚动到最底部找到 Linked Frameworks and Libraries。 点击 + 号并搜索 MapKit.framework, 选中这个框架并点击 Add

img

UITabBarController


UITabBarController 保存了一个视图控制器的数组。UITabBarController 也在屏幕底部维护了一个 tab bar, 数组中每个视图控制器都带有一个 tab bar。触摸标签(tab)会呈现跟该标签(tab)相关联的视图控制器。

打开 Main.stroyboard 并选择 View Controller。 从 Editor 菜单中, 选择 Embed In -> Tab Bar Controller。 这会把 View Controller 添加到 Tab Bar Controller 的视图控制器数组中去。

按住 Control 键从 Tab Bar Controller 拖拽到 Conversion View Controller 上。在弹出的 Relationship Segue 一栏, 选择 view controllers

img

构建并运行该程序。此时标签上仅仅显示的文字是默认的 "Item"。在下一节, 你可以更新 tab bar items 以使 tabs 更具描述性。

UITabBarController 自身是一个 UIViewController 的子类。 UITabBarControllerview 是一个含有两个子视图的 UIView: 即 tab bar 和 所选择的视图控制器的 view

img

Tab bar items


tab bar 上的每个标签(tab)能展示一个标题(title)和图片(image), 为了这个目的, 每个视图控制器维护了一个 tabBarItem 属性。当视图控制器被包含在 UITabBarController 中时, 该视图控制器的 tab bar item 会出现在 tab bar 中。

img

Assets.xcassets 中拖入素材。

tab bar item 属性既能通过 storyboard 也能通过编程来设置。

在 storyboard 中, 定位到 View Controller。 注意, 当视图控制器将被呈现在 tab bar controller 时, 带有 tab bar itemtab bar 被添加到界面中。这在布局你的界面时会很有用。

选择这个 tab bar item 并打开它的属性检查器。 在 Bar Item 栏, 把 Title 设置为 "Map" 并从 Image 菜单中选择 MapIcon。你也可以在画布中双击文本来更改 tab bar item 的文本。

img

你还可以拖拽 tab bar item 以改变它们呈现的位置。

Loaded and Appearing Views


当程序启动时, tab bar controller 默认会加载它的数组中的第一个视图控制器的 view, 即 ConversionViewController。 这意味着 MapViewController 的 view 直到用户点击它的时候才被加载。

你可以自己测试这种懒加载行为。当视图控制器加载完它的视图后, 会调用 viewDidLoad() 方法, 你可以重写该方法以打印信息到控制台中。

你将为这两个视图控制器写代码。 然而, 展示 map 的视图控制器当前并没有代码与之关联, 因为所有的配置都是使用 storyboard。你需要创建一个视图控制器的子类并把它关联到界面中。

创建一个名为 MapViewController 的 UIViewController 子类:

import UIKit

class MapViewController: UIViewController {
    
}

打开 storyboard 并选中该 map 的视图控制器。打开它的身份检查器并把它的 Class 更改为 MapViewController

现在你把 MapViewController 类和画布中的视图控制器关联了起来, 你可以在 ConversionViewControllerMapViewController 中添加代码了。

在 ConversionViewController.swift 中重写 viewDidLoad() 方法,

override func viewDidLoad() {
    // Always call the super implementation of viewDidLoad
    super.viewDidLoad()
    print("ConversionViewController loaded its view.")
}

在 MapViewController.swift 中重写同一个方法:

override func viewDidLoad() {
    // Always call the super implementation of viewDidLoad
    super.viewDidLoad()
    print("MapViewController loaded its view.")
}

程序启动时就打印 ConversionViewController loaded its view, 当点击 Map Tab 时才打印 MapViewController loaded its view。并且都只会打印一次。 如果想执行多次某个事件, 应重写 viewWillAppearviewWillDisappear

访问子视图


通常, 在界面出现在用户面前之前, 你需要在 Interface Builder 中定义的子视图中做某些额外的初始化或配置。 所以你从哪里访问子视图? 有两种主要的观点, 取决于你需要干什么。一个地方是在 viewDidLoad() 方法中, 该方法在视图控制器的界面文件被加载之后调用, 这时视图控制器的所有 outlets 将会引用合适的对象。另外一个地方是在 viewWillAppear(_:) 中。这个方法在视图控制器的 view 被添加到 window 上之前被调用。

你应该选择哪个方法? 在程序运行期间, 如果配置只需要执行一次, 就重写 viewDidLoad() 。 如果需要在每次视图控制器的 view 出现在屏幕之前执行配置, 那么重写 viewWillAppear(_:) 方法。

跟视图控制器和它们的视图交互


让我们看看在视图控制器和它的视图的生命周期中所调用的方法。

  • init(coder: ) 是从 storyboard 创建的 UIViewController 实例的初始化函数。

当从 storyboard 创建视图控制器实例时, 会调用一次它的 init(coder:) 方法。在第 15 章中你会学到更多关于该方法的东西。

  • init(nibName:bundle: )UIViewController 的指定初始化构造函数。

当不使用 storyboard 创建视图控制器实例时, 会调用一次它的 init(nibName:bundle: ) 方法。注意在某些 app 中, 你可以创建几个同样的视图控制器类的实例。每创建一个视图控制器就调用一次该方法。

  • 重写 loadView() 以编程方式创建视图控制器的 view。
  • 重写 viewDidLoad 以配置通过加载界面文件创建的视图。该方法在视图控制器的 view 被创建之后调用。
  • 重写 viewWillAppear(_:) 以配置通过加载界面文件创建的视图

该方法和 viewDidAppear(_:) 会在每次视图控制器在移动到屏幕上时被调用。viewWillDisappear(_:)viewDidDisappear(_:) 会在每次视图控制器移出屏幕时调用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容