UIKit是开发iOS应用程序时最常使用的框架。 它定义了iOS应用程序的核心组件,从标签和按钮到表格视图和导航控制器。 在本文中,我们不仅将开始UIKit框架的探索,还将探索iOS项目的内部结构和iOS应用程序的基本构建块。
什么是UIKit框架?
虽然Foundation框架为iOS和OS X开发定义了类,协议和功能,但UIKit框架专门针对iOS开发。 它等效于OS X开发的Application Kit或AppKit框架。
与Foundation一样,UIKit定义类,协议,函数,数据类型和常量。 它还通过使用Objective-C类别为各种Foundation类(例如NSObject , NSString和NSValue添加了附加功能。
使用Objective-C类别是一种方便的方法,可以在现有类中添加额外的方法,而无需子类化。 它们类似于Swift扩展。 如果您想了解有关Objective-C类别的更多信息,请阅读Aaron Crabtree的 本教程 。
与其像在Foundation框架中那样探索UIKit的关键类,不如创建并经历一个新的iOS项目,探索我们遇到的类。 通过采用这种方法,将很快清楚地知道在什么上下文中使用了一个类,每个类如何适合iOS应用程序的更广泛方案以及它扮演的角色。
一个新的开始
从文件菜单中选择新建>项目... ,启动Xcode并创建一个新项目。 在左侧的iOS部分中,选择“ 应用程序”类别。 从项目模板列表中,选择“ 单一视图应用程序”模板。
Single View Application模板包含iOS应用程序的基本构建块,这使其成为开始我们的旅程的好地方。
将项目命名为FirstSteps,然后输入组织名称和标识符。 将语言设置为Swift并将设备设置为iPhone 。 取消选中底部的复选框。

通过在My Mac上选中创建Git存储库复选框,告诉Xcode您要将新项目保存到何处,并确保将项目置于版本控制下。 请重新访问本文 ,以获取有关版本控制及其好处的更多信息。
文件和文件夹
自从上次从头创建iOS项目以来,我们已经学到了很多新东西,因此最好探索新项目的各种文件和文件夹,看看它们是否响了起来。
在Project Navigator中 ,您应该在项目的根目录中看到两个文件夹:
- 产品展示
- 一个带有项目名称的文件夹,在此示例中为FirstSteps
让我们看一下每个文件夹的内容。
产品展示
产品文件夹当前包含一项。 它带有项目的名称,并具有.app扩展名。 Products文件夹包含一个或多个应用程序,这些应用程序是在源代码编译后由项目创建的。
您是否注意到FirstSteps .app以红色突出显示? 每当Xcode无法找到文件时,它都会以红色突出显示该文件。 不过不要担心。 由于尚未编译项目,因此Xcode尚未创建产品。
项目文件夹
您的大部分时间都花在项目文件夹中,该文件夹当前包含六个文件。 前两个文件AppDelegate.swift和ViewController .swift是源文件。 这些文件包含应用程序的源代码。
Main.storyboard包含应用程序的用户界面。 我们已经在本系列前面的情节提要中使用过。 注意,还有另一个故事板, LaunchScreen.storyboard 。 启动应用程序时,操作系统将使用此情节提要。 操作系统没有显示空视图,而是使用此情节提要板动态创建启动图像,该图像在加载应用程序时显示给用户。
Info.plist ,通常称为项目的“ info-dot-plist”文件,是一个包含各种配置设置的属性列表。 这些设置中的大多数也可以通过以下方式修改:在“ 项目浏览器”中选择项目 ,在“ 目标”列表中选择目标 ,然后打开“ 常规” ,“ 功能 ”和“ 信息”选项卡。
Assets.xcassets是一种特殊类型的文件夹,用于存储项目的资产,例如图像。
应用组件
既然我们知道了项目中不同的文件和文件夹的用途,现在是时候探索iOS应用程序的不同组件了。 在继续前进的过程中,我们将遇到几个属于UIKit的类。 属于UIKit框架的每个类都以类前缀UI开头。 请记住,Foundation类以NS为前缀。
模型-视图-控制器模式
在我们开始探索UIKit框架之前,我想谈谈Model-View-Controller(MVC)模式。 MVC模式是面向对象编程中最广泛使用的模式之一。 它提高了代码的可重用性,并且与职责分离或关注点的概念紧密相关。 MVC模式的主要目标之一是将应用程序的业务逻辑与表示层分离。
Cocoa Touch包含MVC模式,这意味着了解它是什么以及它如何工作很重要。 换句话说,通过了解MVC模式,将更容易掌握iOS应用程序的不同组件如何协同工作。
在MVC模式中,模型层控制着应用程序的业务逻辑。 例如,与数据库交互是模型层的责任。 视图层将由模型层管理的数据呈现给用户。 视图层管理用户界面和用户输入。
控制器是模型层和视图层之间的粘合剂。 虽然模型层和视图层不知道彼此的存在,但控制器却两者都知道。
因为控制器了解模型和视图,所以它通常是应用程序中最少可重用的部分。 对象对环境及其交互的对象了解得越少,重用就越容易。
UIApplication
即使UIApplication类是每个iOS应用程序的关键组成部分,您也不会经常与之交互,并且即使有过,您也很少会觉得需要UIApplication 。
启动应用程序时,将创建此类的单例。 您还记得什么是单例对象吗? 这意味着在应用程序的生命周期内只能创建UIApplication类的一个对象实例。
UIApplication实例是用户交互的入口点,它将事件分配到适当的目标对象。 几分钟后,当我们查看视图控制器时,其确切含义将变得清晰。
在iOS应用程序中, UIApplication实例具有与之关联的委托对象。 每当您使用提供的模板之一创建iOS项目时,Xcode都会为您创建一个应用程序委托类。 在“ 项目浏览器”的项目文件夹中查看源文件的名称。 第一个文件名为AppDelegate.swift 。
此类的实例是UIApplication单例的委托。 在仔细研究AppDelegate类之前,我们需要了解什么是委托模式。
Ole Begemann写了一篇出色的文章,介绍了典型iOS应用程序的启动顺序。 Ole在他的文章中讨论了所涉及的各种组件及其在应用程序启动过程中的作用。 如果您想更好地了解UIApplication类的角色,我强烈建议您阅读本文。
委托模式
委托模式已在Cocoa和Cocoa Touch中广泛使用。 在本系列的后续文章中,我们将探讨表视图的来龙去脉,您将发现表视图在很大程度上依赖于委托(和数据源)模式。
像MVC模式一样,委托在面向对象的编程中很常见。 但是,Cocoa Touch中的委托模式略有不同,因为它利用委托协议来定义委托对象的行为。
让我们继续前进,看看表视图。 如果您花了很多时间在iPhone或iPad上,那么UITableView类应该很熟悉。 它向用户显示数据的有序列表,并且可以很好地完成此工作。
轻按一行时,表视图如何知道该怎么办? 此行为是否包含在UITableView类中? 当然不是,因为此行为因应用程序而异。 如果我们将这种行为包含在UITableView类中,它将不会非常重用。
表格视图将此职责外包给委托对象。 换句话说,它将这个任务委托给另一个对象,一个委托对象。 花点时间检查UITableView类的类引用 。 它具有两个名为dataSource和delegate属性。 当用户点击一行时,表视图会通知该delegate 。 委托对象负责响应该触摸事件。
表格视图的数据源是相似的。 主要区别在于,表视图向数据源对象询问某些内容,即它需要显示的数据。
委托和数据源对象,例如表视图的delegate和dataSource对象,几乎总是自定义类。 在大多数情况下,由开发人员创建和实现这些类,因为它们的实现是特定于每个应用程序的。
申请代表
现在我们知道了什么是委派,是时候探索为我们创建的AppDelegate类Xcode了。 在应用程序启动时,应用程序创建AppDelegate类的实例。 然后,将此AppDelegate实例设置为为您的应用程序创建的操作系统UIApplication实例的委托。 您永远不会显式实例化应用程序委托对象。
打开AppDelegate.swift以检查AppDelegate类的实现。 忽略顶部的注释,第一行将导入UIKit框架,以便我们可以使用其类和协议。
import UIKit在下一行,我们看到一个尚未涉及的属性。 Swift中的属性以@符号开头,可以看作是编译器的指令。 @UIApplicationMain属性告诉编译器AppDelegate是应作为应用程序委托使用的类。 到目前为止,您只需要了解此属性。
@UIApplicationMain下一行应该看起来很熟悉。 这是AppDelegate类的声明的开始。 它指定类的名称以及该类的父类UIResponder 。
它还告诉编译器AppDelegate符合UIApplicationDelegate协议。 这并不奇怪,因为我们已经知道AppDelegate充当应用程序的委托。
class AppDelegate: UIResponder, UIApplicationDelegate {
...
}下一行是window属性的属性声明。 请注意,该属性是UIWindow?类型的变量UIWindow? 。 UIWindow类是UIView的子类, UIView是iOS上视图的基类。
var window: UIWindow?AppDelegate类的接口中最有趣的部分是UIApplicationDelegate协议。 查看UIApplicationDelegate协议的参考,以获取协议定义的方法的完整列表。
该协议定义了许多方法,我鼓励您探索其中的一些方法,以了解该协议的功能。 在这一点上,我们最感兴趣的方法是application(_:didFinishLaunchingWithOptions:) 。
当UIApplication对象完成启动应用程序的准备时,它将通知其委托AppDelegate对象该应用程序即将启动。
为什么它将此事件通知应用程序委托? UIApplication实例将此事件通知其委托人,以便它有机会为应用程序启动做准备。 如以下所示, application(_:didFinishLaunchingWithOptions:)的实现非常短。
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}它提供了对UIApplication实例的引用和选项字典。 您可以暂时忽略选项字典。 为确保应用程序由操作系统启动,我们返回true 。
故事板
Xcode项目包含另一个有趣的文件Main.storyboard 。 故事板定义了应用程序的用户界面。 默认情况下,情节提要板名为Main.storyboard 。 选择情节提要以将其打开。
情节提要当前在中央工作区中包含一个视图。 在项目浏览器的右侧,您可以看到项目列表,这些项目是您在视图中看到的对象。 顶层项目View Controller Scene包含一个子项目View Controller 。
View Controller对象也有许多子项,但是有一个我们特别感兴趣的子项, 名为View的对象。 记住有关MVC模式的讨论。 现在,您可以看到正在运行的MVC模式。 该模型目前尚不存在,但是我们确实有一个视图View对象和一个控制器View Controller对象。
启动应用程序时,情节提要用于创建应用程序的用户界面。 视图控制器自动实例化,视图控制器的视图也自动实例化。 情节提要中的View对象由视图控制器管理。
等一下。 在情节提要中的哪里可以找到视图控制器的类? 如何更改其行为以创建唯一的应用程序? 选择左侧的View Controller对象,然后打开右侧的Identity Inspector 。
身份检查器会告诉您所有您需要了解的内容。 在“ 自定义类 ”部分的顶部,您可以看到视图控制器的类ViewController 。 您是否注意到我们尚未讨论的文件具有相同的名称? 我们将在稍后讨论该文件。
为我们实例化了视图控制器,因为它是情节提要的初始视图控制器。 这在情节提要中通过指向“ 视图控制器场景”的箭头指示。

UIViewController
如果打开ViewController.swift ,您会注意到ViewController类是UIViewController的子类。 与AppDelegate一样, UIViewController类是UIResponder的子类。 视图控制器或其子类属于MVC模式的控制器类别。 顾名思义,它们控制一个视图,即UIView类的实例,该视图属于MVC模式的视图类别。
稍后我们将看到,视图控制器管理一个视图及其子视图。 为此,视图控制器需要了解视图。 换句话说,它需要引用该视图。
情节提要中的视图控制器具有对该视图的引用。 您可以通过在情节提要中选择视图控制器并打开右侧的Connections Inspector来验证这一点。
在“ 连接”检查器中 ,应该看到名为“ 插座”的部分。 “出口”一词是您可以在情节提要中设置的属性的花哨词。 将鼠标悬停在名为视图的出口上,观察工作区中的视图如何突出显示。 那就是视图控制器和视图之间的连接。
UIView
即使您的应用程序只能有一个UIWindow实例,它也可以有很多视图。 UIView类是UIKit框架的重要组成部分,因为许多类直接或间接地继承自UIKit。
通过选择Main.storyboard来重新访问它,并查看Inspector底部的Object Library 。

浏览对象库,然后将标签和按钮拖到工作区中的视图。 只要将它们放置在视图控制器的视图中,将它们放置在视图中的位置都没有关系。
请注意,两个新对象已添加到左侧的“ 对象”部分。 标签( UILabel )和按钮( UIButton )都继承自UIView 。 您是否注意到Label和Button对象与View对象相比略有缩进? 这表明Label和Button对象是View对象的子视图。 一个视图可以包含一个或多个子视图。
如前所述, UIView类是UIKit的重要组成部分。 视图管理屏幕上的矩形区域或框架。 它管理区域,子视图以及与视图内容的任何交互的内容。 UIView类是UIResponder的子类。 在本系列课程中,您将学到更多关于视图的知识。
网点
让我们看一个示例,以说明情节提要,其包含的视图和视图控制器之间的关系。 这三个部分很重要,我想确保您了解它们是如何协同工作的。
不久前,您在视图控制器的视图中添加了标签和按钮。 视图控制器如何知道这些对象? 目前,它们尚未出现在Connections Inspector中 ,但是我们可以通过将它们告知视图控制器来进行更改。 打开ViewController.swift并为标签添加一个属性,为按钮添加一个属性。
import UIKit
class ViewController: UIViewController {
@IBOutlet var myLabel: UILabel!
@IBOutlet var myButton: UIButton!
...
}通过将@IBOutlet属性添加到属性声明中,属性将出现在情节@IBOutlet的“ 连接”检查器中,这就是我们想要的。
回到情节提要,在“ 视图控制器场景”中选择“ 视图控制器”对象,然后打开右侧的“ 连接”检查器 。 现在,新属性在“ 插座 ”列表中列出。 但是,视图控制器尚未在新属性和情节提要中的对象之间建立连接。
这很容易补救。 从myLabel出口左侧的空圈拖动到工作区中的标签。 这将创建连接。 现在,视图控制器知道标签。 对按钮重复此步骤。
即使我们可以在情节提要中更改标签的文本,我们还是在视图控制器中执行此操作,以说明视图控制器可以访问情节提要中的标签和按钮。
打开ViewController.swift,然后查找viewDidLoad()方法。 修改viewDidLoad()方法以反映以下实现。 为了清楚起见,省略了评论。
override func viewDidLoad() {
super.viewDidLoad()
myLabel.text = "This is an instance of a UILabel."
}我们可以通过访问视图控制器的myLabel属性将消息发送到label属性。 我们可以通过使用字符串文字设置标签的text属性来更改标签的text 。
myLabel.text = "This is an instance of a UILabel."当视图控制器加载其视图时,将自动调用viewDidLoad()方法。 override关键字表示我们正在重写由继承树中更高级别的类定义的方法。 UIViewController类( ViewController类的父类)实现此方法。
还要注意,我们在super上调用viewDidLoad() 。 什么是super ? 就像self指向当前实例一样, super指向父类UIViewController 。 换句话说,我们在超类上调用viewDidLoad()方法。 在重写子类中的方法时,这通常很重要,因为超类可能正在其自己的实现中执行重要的任务,并且我们不想破坏任何东西。
通过单击左上方的“运行”按钮在模拟器中运行您的应用程序。 请注意,标签的文本已更新。 不用担心标签和按钮的位置。 我们将在下一个教程中解决此问题。
动作
在本文中,我们探索了许多新事物。 我想通过谈论动作来结束本期文章。 就像出口一样,动作只不过是您可以在情节提要中访问的方法。
让我们看看它是如何工作的。 打开ViewController.swift并将以下方法添加到viewDidLoad()方法下面。
@IBAction func changeColor(sender: UIButton) {
print(sender.classForCoder)
print(sender.superclass)
let r = CGFloat(arc4random() % 255)
let g = CGFloat(arc4random() % 255)
let b = CGFloat(arc4random() % 255)
let color = UIColor(red: (r/255.0), green: (g/255.0), blue: (b/255.0), alpha: 1.0)
view.backgroundColor = color
}不要被@IBAction属性所迷惑。 此属性指示该方法是一种操作,因此可以在情节提要中访问。 如果我们仔细观察一下changeColor(_:)动作,我们可以看到它带有一个UIButton类型的参数。
顾名思义,该方法或操作的参数是将消息发送到视图控制器的对象。 我将稍作解释。
重新访问情节提要,在“ 视图控制器”场景中选择“ 视图控制器”对象,然后打开“ 连接”检查器 。 Connections Inspector中的新部分出现了, Received Actions ,本部分列出了我们刚刚添加的操作。

从操作左侧的空圆圈拖动到工作区中的按钮。 将会出现一个带有选项列表的弹出菜单。 该列表包含按钮可以响应的所有可能的事件。 我们感兴趣的一个是Touch Up Inside 。 当用户触摸按钮并在按钮范围内抬起手指时,会触发此事件。
再次运行您的应用程序,然后点击按钮。 每次您单击按钮时,视图控制器的视图应更改颜色。 我们向changeColor(_:)操作添加了两个打印语句。 让我们看看点击按钮时的输出结果。
UIButton
Optional(UIControl)第一行显示发送方的类,即UIButton的实例。 这证明是在视图控制器上触发此方法的按钮。 它正在向视图控制器发送一条changeColor(_:)消息。
第二行显示发送者的超类。 请记住,并非每个类都有一个超类。 这就是我们返回可选内容的原因。 输出告诉我们UIButton的父类是UIControl 。
该方法本身非常简单。 我们生成介于0和255之间的三个随机整数,将这些值传递给init(red:green:blue:alpha:)以生成随机颜色,并使用随机生成的颜色更新视图控制器视图的背景颜色。 请注意, view引用了视图控制器管理的视图。
结论
在本文中,我们探讨了UIKit框架的一些类,并仔细研究了iOS应用程序的各个组件。 在本系列的其余部分中,我们将更详细地探索和使用UIKit框架。 如果您不完全理解各种概念和模式,那么我相信您会随着系列的进行而不断前进。
如果您有任何问题或意见,可以将其留在下面的评论中,或通过Twitter与我联系。
翻译自: https://code.tutsplus.com/tutorials/ios-from-scratch-with-swift-first-steps-with-uikit--cms-25461