从头开始快速学习:继承和协议

如果您已经阅读了本系列的上一课,那么现在您应该已经对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

在Xcode中设置项目

步骤2:配置项目

将项目命名为ToDo并将Language设置为Swift 。 确保“ 设备”设置为“ iPhone”,并且未选中底部的复选框。 单击下一步继续。

在Xcode中配置项目

告诉Xcode您要将项目存储在何处,然后单击右下角的“ 创建 ”以创建您的第一个Swift项目。

2.项目解剖

在继续进行Swift之旅之前,让我们花点时间看看Xcode为我们创建了什么。 如果您不熟悉Xcode和iOS开发,那么其中大部分内容对您来说都是新手。 但是,通过使用Swift项目,您将更好地了解类和结构的外观以及它们在Swift中的行为。

该项目模板与使用Objective-C作为编程语言创建的项目没有太大区别。 最重要的区别与AppDelegateViewController类有关。

如果您过去使用过Objective-C,那么您会注意到项目模板包含的文件更少。 在我们的项目中找不到头( .h )或实现( .m )文件。 在Swift中,类没有用于声明接口的单独头文件。 而是在单个.swift文件中声明和实现一个类。

我们的项目当前包含两个Swift文件,一个用于AppDelegateAppDelegate.swift ,另一个用于ViewControllerViewController.swift 。 该项目还包括两个情节提要Main.storyboardLaunchScreen.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类中实现UITableViewDataSourceUITableViewDelegate协议。 这涉及几件事。

步骤1:遵守协议

我们需要告诉编译器ViewController类符合UITableViewDataSourceUITableViewDelegate协议。 该语法看起来类似于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中, UITableViewCelltextLabel属性声明为可选类型,因此为问号。 如果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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值