如果您已经阅读了本系列的上一课,那么现在您应该已经对Swift编程语言的基础有了很好的了解。 我们讨论了变量,常量和函数,在上一课中,我们介绍了Swift中面向对象编程的基础。
虽然游乐场是与Swift一起玩并学习语言的好工具,但现在该继续并在Xcode中创建我们的第一个Swift项目了。 在本课程中,我们将使用Xcode和Swift创建一个简单的待办应用程序的基础。 在此过程中,我们将学习更多有关面向对象的编程的知识,并且还将仔细研究Swift和Objective-C的集成。
先决条件
如果您想跟我一起学习,请确保您的计算机上安装了Xcode 8.3.2或更高版本。 Xcode 8.3.2可从Apple的App Store中获得 。
1.项目设置
步骤1:选择模板
启动Xcode 8.3.2或更高版本,然后从“ 文件”菜单中选择“ 新建”>“项目... ”。 在iOS部分中,选择Single View Application模板,然后单击Next 。
步骤2:配置项目
将项目命名为ToDo并将Language设置为Swift 。 确保“ 设备”设置为“ iPhone”,并且未选中底部的复选框。 单击下一步继续。
告诉Xcode您要将项目存储在何处,然后单击右下角的“ 创建 ”以创建您的第一个Swift项目。
2.项目解剖
在继续进行Swift之旅之前,让我们花点时间看看Xcode为我们创建了什么。 如果您不熟悉Xcode和iOS开发,那么其中大部分内容对您来说都是新手。 但是,通过使用Swift项目,您将更好地了解类和结构的外观以及它们在Swift中的行为。
该项目模板与使用Objective-C作为编程语言创建的项目没有太大区别。 最重要的区别与AppDelegate
和ViewController
类有关。
如果您过去使用过Objective-C,那么您会注意到项目模板包含的文件更少。 在我们的项目中找不到头( .h )或实现( .m )文件。 在Swift中,类没有用于声明接口的单独头文件。 而是在单个.swift文件中声明和实现一个类。
我们的项目当前包含两个Swift文件,一个用于AppDelegate
类AppDelegate.swift ,另一个用于ViewController
类ViewController.swift 。 该项目还包括两个情节提要板Main.storyboard和LaunchScreen.storyboard 。 在本课程的稍后部分,我们将使用主故事板。 当前,它仅包含ViewController
类的场景。
项目中还包含其他一些文件和文件夹,但现在我们将忽略它们。 它们在本课程的范围内没有任何重要作用。
3.继承
在本课程中,我们要涉及的第一件事是继承,即面向对象编程中的常见范例。 在Swift中,只有类可以从另一个类继承。 换句话说,结构和枚举不支持继承。 这是类和结构之间的主要区别之一。
打开ViewController.swift以查看继承的作用。 ViewController
类的接口和实现非常简单,这使我们可以更轻松地专注于基本要素。
UIKit
在ViewController.swift的顶部,您应该看到UIKit框架的import语句。 请记住,UIKit框架提供了用于创建功能性iOS应用程序的基础结构。 顶部的import语句可在ViewController.swift中为我们提供此基础结构。
import UIKit
超类
在import语句下面,我们定义一个名为ViewController的新类。 正如我们在本系列文章前面所看到的,类名后面的冒号没有转换为该类型 。 相反,冒号之后的类是ViewController
类的超类。 换句话说,当我们定义一个名为ViewController
的类时,可以读取以下代码片段, 该类继承自UIViewController
。
class ViewController: UIViewController {
}
这也解释了import语句在ViewController.swift顶部的存在,因为UIViewController
类是在UIKit框架中定义的。
覆写
ViewController
类当前包含两个方法,但是请注意,每个方法都以override
关键字为前缀。 这表明方法是在类的超类中定义的,或者在继承树的更高级别中定义,并且被ViewController
类覆盖。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
override
构造在Objective-C中不存在。 在Objective-C中,您在子类中实现了重写的方法,而没有明确指出它重写了继承树上的方法。 Objective-C运行时负责其余的工作。
尽管在Swift中也是如此,但是override
关键字为方法重写增加了安全性。 因为我们为viewDidLoad()
方法添加了override
关键字前缀,所以Swift 希望该方法在类的超类中或更高层次的继承树中。 简而言之,如果您重写继承树中不存在的方法,则编译器将引发错误。 您可以通过拼写错误的viewDidLoad()
方法进行测试,如下所示。
4.用户界面
声明出口
让我们向视图控制器添加一个表格视图以显示待办事项列表。 在此之前,我们需要为表格视图创建一个出口。 插座只不过是在Interface Builder中可见并可以设置的属性。 要在ViewController
类中声明插座,我们在属性(变量)前添加@IBOutlet
属性。
class ViewController: UIViewController {
@IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
请注意,插座是隐式展开的可选。 什么啊 首先,我要指出的是,插座始终必须是可选类型。 原因很简单。 初始化后, ViewController
类的每个属性都需要具有一个值。 但是,只有在ViewController
实例已初始化后才在运行时将插座连接到用户界面,因此为可选类型。
等一下。 tableView
出口被声明为隐式展开的可选,而不是可选。 没问题。 我们可以通过将上面代码片段中的感叹号替换为问号来声明tableView
出口是可选的。 那样编译就可以了。 但是,这也意味着每次我们要访问存储在可选对象中的值时,都需要显式地取消包装属性。 这将很快变得麻烦且冗长。
相反,我们将tableView
出口声明为隐式展开的可选,这意味着如果需要访问其值,则无需显式取消包装该可选。 简而言之,一个隐式解包的可选是可选的,但是我们可以像常规变量一样访问存储在可选中的值。 要记住的重要一点是,如果在未设置任何值的情况下尝试访问其值,则应用程序将崩溃。 那是陷阱。 但是,如果插座正确连接,则可以确保在初次尝试使用插座时已将其设置好。
连接插座
在声明插座的情况下,是时候在Interface Builder中进行连接了。 打开Main.storyboard ,然后选择视图控制器。 从编辑器菜单中选择“ 嵌入”>“导航控制器 ”。 这会将视图控制器设置为导航控制器的根视图控制器。 现在不用担心。
将UITableView
实例从“ 对象库” UITableView
视图控制器的视图,然后添加必要的布局约束。 选中表视图后,打开Connections检查器 ,并将表视图的dataSource
设置为视图控制器, delegate
出口delegate
给视图控制器。
在Connections Inspector仍然打开的情况下,选择视图控制器,然后将tableView
出口连接到我们刚刚添加的表视图。 这tableView
ViewController
类的tableView
出口连接到表格视图。
5.协议
在构建和运行应用程序之前,我们需要在ViewController
类中实现UITableViewDataSource
和UITableViewDelegate
协议。 这涉及几件事。
步骤1:遵守协议
我们需要告诉编译器ViewController
类符合UITableViewDataSource
和UITableViewDelegate
协议。 该语法看起来类似于Objective-C中的语法。
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
...
}
在上面的示例中,类遵循的协议在超类UIViewController
之后列出。 如果一个类没有超类,这在Swift中并不罕见,那么协议会在类名和冒号之后立即列出。
步骤2:实现UITableViewDataSource
协议
由于UITableViewDelegate
协议未定义必需的方法,因此我们现在仅要实现UITableViewDataSource
协议。 在执行此操作之前,让我们创建一个变量属性,以存储要在表格视图中列出的待办事项。
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet var tableView: UITableView!
var items: [String] = []
...
}
我们声明[String]
类型的变量属性items
,并将一个空数组[]
设置为初始值。 现在看起来应该很熟悉。 接下来,让我们实现UITableViewDataSource
协议的两个必需方法。
第一个必需的方法numberOfRows(inSection:)
很简单。 我们只返回存储在items
属性中的items
。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
第二个必需的方法cellForRow(at:)
需要解释。 使用下标语法,我们要求items
提供与当前行相对应的项目。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Fetch Item
let item = items[indexPath.row]
// Dequeue Cell
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath)
// Configure Cell
cell.textLabel?.text = item
return cell
}
然后,我们向表视图询问具有标识符"TableViewCell"
的单元格,并传递当前行的索引路径。 请注意,我们将单元格存储在常量cell
。 无需将cell
声明为变量。
在下一行代码中,我们配置表格视图单元格,并使用item
的值设置文本标签的文本。 请注意,在Swift中, UITableViewCell
的textLabel
属性声明为可选类型,因此为问号。 如果textLabel
不等于nil
则可以textLabel
行代码读取为将文本标签的text
属性设置为item
。 换句话说,仅当textLabel
不为nil
时才设置文本标签的text
属性。 这是Swift中非常方便的安全构造,称为可选链接 。
步骤3:单元重用
在构建应用程序之前,我们需要整理两件事。 首先,我们需要告诉表视图它需要使用UITableViewCell
类来创建新的表视图单元格。 为此,我们调用registerClass(_:forCellReuseIdentifier:)
,传入UITableViewCell
类和我们之前使用的重用标识符"TableViewCell"
。 如下所示更新viewDidLoad()
方法。
override func viewDidLoad() {
super.viewDidLoad()
// Register Class for Cell Reuse
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
}
步骤4:添加项目
我们目前没有任何项目要显示在表格视图中。 通过用几个待办事项填充items
属性,可以轻松解决此问题。 有几种方法可以完成此操作。 我选择在viewDidLoad()
方法中填充items
属性,如下所示。
override func viewDidLoad() {
super.viewDidLoad()
// Populate Items
items = ["Buy Milk", "Finish Tutorial", "Play Minecraft"]
// Register Class for Cell Reuse
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
}
6.构建和运行
现在该轮到我们的应用程序了。 从Xcode的Product菜单中选择Run或点击Command-R 。 如果您一直遵循,那么应该得出以下结果。
请注意,我已经在导航栏中视图顶部添加了标题To Do。 您可以通过在viewDidLoad()
方法中设置ViewController
实例的title
属性来执行相同的操作。
override func viewDidLoad() {
super.viewDidLoad()
// Set Title
title = "To Do"
// Populate Items
items = ["Buy Milk", "Finish Tutorial", "Play Minecraft"]
// Register Class for Cell Reuse
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
}
结论
即使我们刚刚创建了一个简单的应用程序,您仍然学到了很多新东西。 我们已经探讨了继承和覆盖方法。 我们还介绍了协议以及如何在ViewController
类中采用UITableViewDataSource
协议。 但是,您学到的最重要的事情是如何与Objective-C API进行交互。
了解iOS SDK的API是用Objective-C编写的,这一点很重要。 Swift旨在与这些API兼容。 基于过去的失败,Apple理解Swift需要能够挂接到iOS SDK,而不必重写Swift中的每个API。
可以将Objective-C和Swift结合使用,但是在前进的过程中,我们将更加详细地探讨一些警告。 由于Swift一直坚持不懈地致力于安全,因此我们需要时不时地克服一些障碍。 但是,这些障碍中没有一个太大,我们将在下一课中继续学习待办事项。
翻译自: https://code.tutsplus.com/tutorials/swift-from-scratch-inheritance-and-protocols--cms-23334