欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-23 11:07:09
...

如果您已经阅读了本系列的上一课,那么现在您应该已经对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作为编程语言创建的项目没有太大区别。 最重要的区别与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