EDUCBA-Swift-中级-IOS-开发笔记-全-

EDUCBA Swift 中级 IOS 开发笔记(全)

001:视图控制器间数据传递入门 🚀

在本节课中,我们将学习如何在iOS应用的两个视图控制器之间传递数据。我们将使用文本字段(UITextField)作为数据输入和接收的界面元素,并学习如何为这些文本字段设置基本的数据验证规则,例如确保字段不为空以及验证电子邮件格式。


项目创建与设置 🛠️

首先,我们需要创建一个新的Xcode项目。Xcode是苹果公司提供的集成开发环境(IDE),用于为iPhone、Mac和Apple Watch等设备开发应用程序。

以下是创建项目的步骤:

  1. 打开Xcode,选择“Create a new Xcode project”。
  2. 选择“Single View App”模板。
  3. 将项目命名为“PassingData”。
  4. 确保编程语言选择为“Swift”。
  5. 完成创建。

项目创建后,你会看到一个名为ViewController的类和一个对应的故事板(Storyboard)文件。故事板中的视图控制器(View Controller)将由ViewController类来管理其事件和生命周期。


添加第二个视图控制器 ➕

由于我们的主题是在两个视图控制器间传递数据,因此需要创建第二个视图控制器。

以下是添加第二个视图控制器的步骤:

  1. 从对象库(Object Library)中拖拽一个新的“View Controller”到故事板上。
  2. 创建一个新的Cocoa Touch Class文件,继承自UIViewController,例如命名为View2ViewController
  3. 回到故事板,选中新添加的视图控制器,在身份检查器(Identity Inspector)中,将其类(Class)设置为View2ViewController

现在,我们有了两个视图控制器:ViewController(视图1)和View2ViewController(视图2)。数据将从视图1传递到视图2。


设计用户界面 🎨

接下来,我们需要为两个视图控制器设计用户界面。

设计第一个视图控制器(ViewController)

首先,为视图1设置一个背景色以便区分。然后,从对象库中拖拽以下元素到视图上:

  • 一个标签(UILabel),将其文本改为“Enter Details”,并调整其大小和位置。
  • 四个文本字段(UITextField)。文本字段会在界面中创建一个可编辑的文本区域,点击时会弹出键盘。我们将使用它们的placeholder属性来显示提示文本。
  • 一个按钮(UIButton),将其标题改为“Pass Data”,并设置其背景色和文字颜色。

为了能够导航到第二个视图,我们需要为第一个视图控制器嵌入一个导航控制器(Navigation Controller)。在编辑器中,选择第一个视图控制器,然后点击菜单栏的 “Editor” -> “Embed In” -> “Navigation Controller”。

以下是四个文本字段的placeholder建议:

  • 第一个:First Name
  • 第二个:Last Name
  • 第三个:Email
  • 第四个:Phone

设计第二个视图控制器(View2ViewController)

为了节省时间,我们可以复制视图1中的界面元素到视图2,并进行调整:

  1. 为视图2设置一个不同的背景色(例如绿色)。
  2. 复制视图1中的标签和四个文本字段到视图2。
  3. 删除“Pass Data”按钮,因为视图2仅用于显示数据。
  4. 将四个文本字段的placeholder分别改为 Display First NameDisplay Last NameDisplay EmailDisplay Phone。同时,将这些文本字段的enabled属性取消勾选,使其变为不可编辑的只读状态,仅用于显示。

核心概念与代码准备 💡

在开始编写连接和传递数据的代码之前,理解几个核心概念很重要。

文本字段(UITextField):它是一个用于显示可编辑文本的控件。当用户点击文本字段时,它会成为“第一响应者”(First Responder),并自动弹出键盘。当你想关闭键盘时,需要调用该文本字段的resignFirstResponder()方法。

数据传递:我们的目标是将视图1中四个文本字段里用户输入的内容,在点击“Pass Data”按钮后,传递并显示在视图2对应的四个文本字段中。这通常通过属性(Properties)和** segue(转场)** 来实现。

验证:我们将为视图1的文本字段添加简单的验证,例如检查是否为空,以及验证电子邮件格式是否正确。

在下一节中,我们将创建界面元素与代码之间的连接(IBOutlet和IBAction),并实现数据传递的逻辑。


连接界面与代码 🔗

现在,我们需要将故事板中的界面元素与Swift代码连接起来,以便控制它们。

为第一个视图控制器创建连接

ViewController.swift文件中,我们需要为四个文本字段和“Pass Data”按钮创建出口(IBOutlet)和动作(IBAction)。

以下是需要创建的连接:

  1. 为四个UITextField创建IBOutlet,分别命名为 firstNameTextField, lastNameTextField, emailTextField, phoneTextField
  2. 为“Pass Data”按钮创建一个IBAction方法,例如命名为passDataButtonTapped

为第二个视图控制器创建连接

View2ViewController.swift文件中,我们需要为四个用于显示的文本字段创建IBOutlet,以便接收来自第一个视图控制器的数据。

以下是需要创建的连接:

  1. 为四个UITextField创建IBOutlet,分别命名为 displayFirstNameTextField, displayLastNameTextField, displayEmailTextField, displayPhoneTextField

创建连接的方法是:在Xcode中打开助理编辑器(Assistant Editor),按住Ctrl键,从故事板上的控件拖拽到相应的Swift类文件中。


实现数据传递与验证 ✅

所有连接创建完毕后,我们就可以实现核心功能了。

第一步:执行导航与准备数据传递

在第一个视图控制器的ViewController.swift中,我们需要为“Pass Data”按钮和第二个视图控制器之间创建一个segue(例如,Show segue)。然后,在passDataButtonTapped IBAction方法中,我们可以触发这个segue。

但在触发之前,我们应该先进行数据验证。我们将在passDataButtonTapped方法中添加验证逻辑。

第二步:编写验证逻辑

验证逻辑包括:

  • 非空检查:确保所有文本字段都不为空。
  • 邮箱格式验证:使用简单正则表达式检查电子邮件文本字段的格式。
  • 电话号码键盘:将电话号码文本字段的keyboardType属性设置为.phonePad,这样会弹出数字键盘。

如果验证失败,则弹出一个警告框(UIAlertController)提示用户,并不执行页面跳转。

以下是验证函数的框架:

func validateData() -> Bool {
    // 检查 firstNameTextField.text 是否为空
    // 检查 lastNameTextField.text 是否为空
    // 检查 emailTextField.text 是否符合邮箱格式
    // 检查 phoneTextField.text 是否为空
    // 如果任何一项失败,返回 false
    // 全部成功,返回 true
}

第三步:通过Segue传递数据

当验证通过后,segue会被触发。在跳转到第二个视图控制器之前,系统会调用prepare(for:sender:)方法。这是我们传递数据的关键位置。

ViewController.swift中重写prepare(for:sender:)方法:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "YourSegueIdentifier" { // 替换为你的segue标识符
        let destinationVC = segue.destination as! View2ViewController
        destinationVC.receivedFirstName = firstNameTextField.text
        destinationVC.receivedLastName = lastNameTextField.text
        destinationVC.receivedEmail = emailTextField.text
        destinationVC.receivedPhone = phoneTextField.text
    }
}

注意:你需要在View2ViewController类中定义receivedFirstNamereceivedLastName等属性来接收这些数据。

第四步:在第二个视图中显示数据

最后,在View2ViewControllerviewDidLoad方法中,将接收到的数据设置到对应的显示文本字段中:

override func viewDidLoad() {
    super.viewDidLoad()
    displayFirstNameTextField.text = receivedFirstName
    displayLastNameTextField.text = receivedLastName
    displayEmailTextField.text = receivedEmail
    displayPhoneTextField.text = receivedPhone
}

总结 📝

本节课中,我们一起学习了iOS开发中视图控制器间数据传递的基础知识。我们完成了以下任务:

  1. 创建了一个包含两个视图控制器的项目。
  2. 设计了两个视图的用户界面,使用了文本字段、标签和按钮。
  3. 理解了文本字段和第一响应者的概念。
  4. 通过IBOutlet和IBAction将界面与代码连接。
  5. 实现了对用户输入数据的非空验证和邮箱格式验证。
  6. 利用prepare(for:sender:)方法,通过segue将数据从第一个视图控制器传递到第二个视图控制器。
  7. 在第二个视图控制器中成功接收并显示了传递过来的数据。

通过这个完整的流程,你已经掌握了在iOS应用中处理表单输入、验证和页面间数据传递的基本技能。

002:使用文本字段传递数据的关键要点 📱

在本节课中,我们将学习如何在iOS应用中使用文本字段(UITextField)来传递数据。我们将涵盖对象的基本概念、数据传递方法、键盘管理以及输入验证。


概述

在面向对象编程语言中,例如Swift,一切操作都围绕对象进行。假设我们有一个类,并创建了该类的对象。通过这个对象,我们可以访问类中的数据和方法。这就是创建对象的原因。

上一节我们介绍了对象的基本概念,本节中我们来看看如何在视图控制器之间传递文本字段的数据。


创建对象与传递数据

首先,我创建了一个数组。当按下按钮时,按钮触发的操作会将所有文本字段的数据存储到这个数组中。接着,我创建了当前视图控制器类的对象。通过这个对象,我调用了接收数据的数组。

当按钮被调用时,传递的数据数组会自动赋值给接收数组。数据进入接收数组后,借助导航控制器,视图将从View1推送到View2。

以下是核心的数据传递逻辑示例:

// 假设在第一个视图控制器中
@IBAction func passDataButtonTapped(_ sender: UIButton) {
    let dataToPass = [firstNameTextField.text, lastNameTextField.text, emailTextField.text]
    let destinationVC = storyboard?.instantiateViewController(withIdentifier: "SecondVC") as! SecondViewController
    destinationVC.receivedDataArray = dataToPass
    navigationController?.pushViewController(destinationVC, animated: true)
}

如果没有数据,则不会传递任何内容,仅执行导航部分。


管理键盘

当点击文本字段时,它会成为第一响应者,键盘随之出现。然而,如果未设置文本字段放弃第一响应者状态,键盘可能不会自动消失。

为了解决这个问题,我们需要使用文本字段的委托方法。与表格视图类似,文本字段也有委托和数据源方法。我们将使用 textFieldShouldReturn 方法。

以下是实现步骤:

  1. 设置文本字段的委托为当前视图控制器。
  2. textFieldShouldReturn 方法中,让文本字段放弃第一响应者状态,从而使键盘消失。

以下是实现代码:

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var firstNameTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        firstNameTextField.delegate = self
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder() // 隐藏键盘
        return true
    }
}

通过设置文本字段的委托,当用户按下键盘上的“返回”键时,键盘会消失。你可以在该方法中设置断点进行测试。


使用不同类型键盘

文本字段可以配置为显示不同类型的键盘,以适应不同的输入内容,如电子邮件地址或电话号码。

以下是配置方法:

  1. 在故事板中,选择文本字段。
  2. 在属性检查器中,找到“Keyboard Type”选项。
  3. 根据需要选择类型,例如“Email Address”或“Phone Pad”。

例如,电子邮件地址的键盘会包含“@”和“.”符号,而电话键盘则显示数字。

然而,像“Phone Pad”这类键盘没有“返回”键。因此,我们需要另一种方式来隐藏键盘。


使用点击手势隐藏键盘

当键盘没有“返回”键时,我们可以通过点击视图的其他部分来隐藏键盘。这可以通过添加点击手势识别器来实现。

以下是实现步骤:

  1. viewDidLoad 方法中创建点击手势识别器对象。
  2. 将目标设置为当前视图控制器,并指定一个选择器方法(例如 didTapView)。
  3. 将该手势识别器添加到主视图上。

以下是实现代码:

override func viewDidLoad() {
    super.viewDidLoad()
    // ... 其他代码 ...

    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapView))
    self.view.addGestureRecognizer(tapGesture)
}

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/educba-swift-mid-iosdev/img/0c92fdd64bffa2338eb8de7b3f1e8ff2_25.png)

@objc func didTapView() {
    self.view.endEditing(true) // 隐藏所有键盘
}

现在,当数字键盘或其他任何键盘出现时,点击视图的任何地方都可以使键盘消失。这个方法适用于所有文本字段。


添加输入验证

最后,我们需要为文本字段添加验证,确保用户不会传递空数据。

以下是验证逻辑的步骤:

  1. 检查所有必需的文本字段是否为空。
  2. 使用逻辑运算符(||&&)来决定验证条件。
    • && (AND 运算符):所有条件都必须为真,整个表达式才为真。
    • || (OR 运算符):只要有一个条件为真,整个表达式就为真。
  3. 如果验证失败(例如字段为空),则向用户显示一个警告框。

以下是验证和显示警告的示例代码:

@IBAction func submitButtonTapped(_ sender: UIButton) {
    if firstNameTextField.text?.isEmpty == true ||
       lastNameTextField.text?.isEmpty == true ||
       emailTextField.text?.isEmpty == true {

        // 创建警告框
        let alert = UIAlertController(title: "错误", message: "所有字段都必须填写。", preferredStyle: .alert)
        let okAction = UIAlertAction(title: "确定", style: .default, handler: nil)
        alert.addAction(okAction)
        self.present(alert, animated: true, completion: nil)
    } else {
        // 所有字段都有数据,执行数据传递等操作
        // ... 传递数据的代码 ...
    }
}

在这个例子中,我们使用了 || 运算符。只要有一个文本字段为空,条件就为真,并显示警告。我们还需要为电子邮件格式等添加更复杂的验证,但基本逻辑与此类似。


总结

本节课中我们一起学习了使用文本字段传递数据的几个关键要点:

  1. 对象与数据传递:理解了如何通过对象在视图控制器间传递数组数据。
  2. 键盘管理:学会了使用委托方法 textFieldShouldReturn 来响应返回键并隐藏键盘。
  3. 键盘类型:了解了如何为不同输入场景配置特定的键盘类型。
  4. 手势识别:掌握了通过添加点击手势来隐藏没有返回键的键盘。
  5. 输入验证:实现了基本的非空验证,并使用警告框向用户提供反馈。

通过结合这些技术,你可以创建出交互更友好、数据更可靠的iOS应用界面。

003:文本字段控制器导论 📝

在本节课中,我们将学习iOS开发中一个非常基础但至关重要的控件:文本字段。我们将通过创建一个简单的登录表单演示,来深入了解文本字段的属性、配置方法以及如何通过委托来响应用户交互。课程内容将涵盖从界面布局到功能实现的完整流程。


界面搭建与基础属性

上一节我们概述了课程目标,本节中我们来看看如何搭建一个包含两个文本字段和一个按钮的简单登录界面。

首先,我们在主视图控制器上放置两个文本字段。文本字段是UIKit提供的一个基础控件,其主要作用是接收用户的输入,并将用户输入的数据用于程序逻辑或应用程序的运行过程中。

从iOS 8开始,我们可以结合使用自动布局和Auto Layout来适配不同屏幕尺寸。接下来,我将为第二个文本字段和按钮设置Auto Layout约束,并将按钮的背景色从白色改为更醒目的颜色。

文本字段有多种边框样式可供选择,以适应不同的UI设计需求。

以下是主要的边框样式类型:

  • 圆角样式:边框为圆角矩形。
  • 阴影样式:矩形边框,但带有阴影效果。
  • 直角样式:标准的直角矩形边框。
  • 无边框样式:不显示任何边框。

您可以在界面上清晰地看到这些样式的区别。我将选择直角样式进行演示。

文本字段另一个非常重要的属性是占位符文本。占位符文本在用户未输入任何内容时显示,用于提示用户该字段需要输入什么内容。


连接代码与委托

为了在控制器类中访问界面元素,我们需要为文本字段创建出口。遵循良好的命名约定是一个好习惯,这能使其他开发者更容易理解你的代码。我使用“Tf”作为文本字段的缩写前缀。

同时,我也会为按钮创建一个动作。

接下来,我将为文本字段设置委托。委托机制允许我们的控制器类遵循并实现文本字段定义的一系列协议方法,从而响应用户的交互事件。我将在后面简要介绍文本字段的主要委托方法。


核心功能与属性配置

文本字段包含许多控制其行为和外观的属性。

一个重要的属性是清除按钮。我们可以设置它在编辑时出现、除非编辑否则不出现,或者始终可见。当用户点击清除按钮时,它会清空文本字段中已输入的内容。

另一个相关属性是“编辑开始时清除”。如果启用此功能,当用户结束编辑后再次开始编辑时,之前输入的内容会被自动清除。让我通过编译程序来演示其效果。

现在,当我输入文字并点击清除按钮时,文字被清空,占位符文本重新显示。但当我再次点击文本字段开始输入时,之前的文字“test”并未被清除,因为我尚未启用“编辑开始时清除”功能。启用该功能后再次编译,可以看到差异:再次开始编辑时,原有文本会被自动清除。

我现在将禁用此功能。

另一个重要功能是最小字体大小。例如,在屏幕较大的iPhone 6上,长文本可能不会被截断,但在屏幕较小的iPhone 4s上,同样的文本可能会被截断。设置最小字体大小可以确保在屏幕缩小时,字体自动缩小以避免文本被截断。

其他属性还包括:

  • 自动大写:设置首字母是否自动大写。
  • 自动更正:启用或禁用自动更正功能。
  • 拼写检查:启用或禁用拼写检查。

这些功能在启用后,文本字段会自动处理相应的任务。

一个非常关键的属性是键盘类型。例如,默认打开的是字母键盘。通过将键盘类型设置为“电话键盘”,文本字段将默认打开数字键盘,用户只能输入数字。这在需要输入电话号码、社保号或卡号时非常有用。

我们还可以设置键盘的外观为深色或浅色。

回车键属性可以改变键盘右下角按钮的文本,默认是“换行”。我们可以将其改为“下一个”等其他选项。

自动启用回车键功能决定了回车键何时可用。通常,当有文本输入时,回车键才变为可点击状态。

安全文本输入是文本字段的一个非常重要的特性。当我们需要接收用户的敏感信息(如密码)时,可以启用此功能。启用后,输入的文字会显示为圆点,从而防止他人窥视。


文本字段委托详解

为了让文本字段响应更复杂的交互,我们需要让控制器遵循UITextFieldDelegate协议。

以下是几个基本的文本字段委托方法及其调用时机:

  • textFieldShouldBeginEditing::当我们点击文本字段准备开始编辑时调用。它询问代理是否允许开始编辑。
  • textFieldDidBeginEditing::当我们已经开始在文本字段中输入文本时调用。
  • textFieldShouldEndEditing::当我们按下回车键或结束编辑,键盘即将隐藏时调用。它询问代理是否允许结束编辑。
  • textFieldDidEndEditing::在键盘隐藏之后调用。
  • textField:shouldChangeCharactersInRange:replacementString::当文本字段的内容即将改变时调用。常用于限制输入字符的长度或格式。
  • textFieldShouldClear::当清除按钮被点击时调用。通常用于在清空前执行一些逻辑。
  • textFieldShouldReturn::当用户按下键盘上的回车键时调用。通常在此方法中隐藏键盘。

为了演示这些委托方法的调用流程,我将在方法中添加打印日志,输出当前文本字段的占位符文本,以便清晰了解是哪个文本字段的哪个方法被调用了。

让我运行程序并展示其效果。当我点击第一个文本字段(用户名)时,控制台会打印textFieldDidBeginEditing被调用。当我点击第二个文本字段(密码)时,会先调用第一个文本字段的textFieldDidEndEditing,再调用第二个文本字段的textFieldDidBeginEditing。当我点击回车键时,会触发textFieldShouldReturn,然后是textFieldDidEndEditing


功能集成演示

最后,我将把密码文本字段标记为安全输入字段。当我输入用户名,然后点击密码字段输入时,可以看到密码被隐藏为圆点。点击之前创建的按钮,可以清空两个文本字段的内容。整个过程中,委托方法会按照上述序列被调用。


本节课中我们一起学习了文本字段的基础知识,包括其属性配置、键盘类型设置、安全输入以及如何通过委托方法响应用户交互。这是一个关于文本字段如何工作的基础演示,在接下来的课程中,我们将继续深入探讨iOS的其他控件和高级特性。

004:Core Data入门指南 🗄️

在本节课中,我们将学习如何在iOS应用中使用Core Data框架。Core Data是一个强大的对象图管理和持久化框架,它允许开发者以面向对象的方式操作数据,而无需直接编写SQL语句。我们将从创建一个支持Core Data的项目开始,逐步讲解其核心概念和基本操作。

概述

我们将创建一个简单的项目来演示Core Data的基本用法。首先,需要创建一个新的Xcode项目,并确保勾选“Use Core Data”选项。这将在项目中自动集成Core Data所需的初始配置和文件。

创建项目与数据模型

上一节我们介绍了课程概述,本节中我们来看看如何创建项目并设置数据模型。

  1. 打开Xcode,选择“Create a new X project”。
  2. 选择“Single View Application”模板。
  3. 将项目命名为“Database”。
  4. 在项目设置中,务必勾选“Use Core Data”选项。
  5. 将语言设置为Swift。

创建完成后,Xcode会自动生成一个名为Database.xcdatamodeld的文件,这是Core Data的数据模型文件。同时,在AppDelegate.swift中,也会生成管理Core Data栈的相关代码。

理解Core Data的核心组件

在开始编码之前,理解Core Data的几个核心概念至关重要。

  • 实体 (Entity):实体类似于数据库中的表或面向对象编程中的类。它定义了要存储的数据结构。
  • 属性 (Attribute):属性是实体的组成部分,用于存储具体的数据,类似于类中的实例变量。例如,一个“用户”实体可以有“姓名”(字符串类型)和“年龄”(整数类型)属性。
  • 托管对象 (Managed Object):托管对象是实体的实例。let newUser = User(context: context) 这行代码就创建了一个User实体的托管对象。我们通过操作这个对象来保存或修改数据。
  • 持久化存储协调器 (Persistent Store Coordinator)托管对象上下文 (Managed Object Context):Core Data通过一个“栈”来工作。我们通常不直接与底层的SQLite数据库(持久化存储)交互,而是通过托管对象上下文来操作。上下文管理着所有托管对象的生命周期,并将更改保存到持久化存储中。在AppDelegate中,可以通过 persistentContainer.viewContext 来获取主上下文。

设计数据模型

现在,我们在图形化界面中设计数据模型。

  1. 打开Database.xcdatamodeld文件。
  2. 点击左下角的“Add Entity”按钮。
  3. 将实体名称重命名为“User”。
  4. 在“Attributes”区域,点击“+”号添加两个属性:
    • 第一个属性:名称 name,类型 String
    • 第二个属性:名称 age,类型 Integer 16

至此,我们已定义好一个简单的User实体。

保存数据到Core Data

上一节我们设计了数据模型,本节中我们来看看如何编写代码将数据保存到Core Data中。

首先,在需要使用Core Data的视图控制器(如ViewController.swift)顶部导入框架并获取上下文。

import UIKit
import CoreData

class ViewController: UIViewController {
    // 获取应用委托实例以访问Core Data栈
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    // 获取托管对象上下文
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

    override func viewDidLoad() {
        super.viewDidLoad()
        // 调用保存数据的方法
        saveUserData()
    }

    func saveUserData() {
        // 1. 创建User实体的一个托管对象
        let newUser = User(context: context)

        // 2. 为托管对象的属性赋值
        newUser.name = "Rohan"
        newUser.age = 24

        // 3. 通过上下文保存数据到持久化存储
        do {
            try context.save()
            print("数据保存成功!")
        } catch {
            print("保存数据时出错: \(error)")
        }
    }
}

以下是代码执行步骤的分解:

  1. 使用User(context: context)在指定的上下文中创建一个新的User托管对象。
  2. 像设置普通对象属性一样,为newUsernameage赋值。
  3. 调用context.save()方法。此操作可能抛出错误,因此需要用do-try-catch块包裹。

从Core Data中获取数据

数据保存后,我们需要能够将其读取出来。这通过获取请求 (Fetch Request) 来实现。

ViewController中添加一个方法来获取并打印所有用户数据:

func fetchUserData() {
    // 1. 创建一个针对User实体的获取请求
    let fetchRequest: NSFetchRequest<User> = User.fetchRequest()

    do {
        // 2. 执行获取请求,返回一个结果数组
        let users = try context.fetch(fetchRequest)

        // 3. 遍历并处理结果
        if users.count > 0 {
            for user in users {
                if let userName = user.name {
                    print("姓名: \(userName), 年龄: \(user.age)")
                }
            }
        } else {
            print("没有找到用户数据。")
        }
    } catch {
        print("获取数据时出错: \(error)")
    }
}

可以在viewDidLoad中调用fetchUserData()来测试。执行后,控制台应输出之前保存的用户信息。

调试与验证

为了验证保存操作是否真正触发了Core Data的持久化流程,可以在AppDelegate.swiftsaveContext()方法中设置一个断点。

  1. 在Xcode中打开AppDelegate.swift
  2. 找到saveContext()函数。
  3. 在其内部代码行左侧的边栏点击,设置一个断点(蓝色箭头)。
  4. 再次运行应用并执行保存操作。
  5. 如果程序在断点处暂停,说明保存流程已成功调用至Core Data栈的底层。

总结

本节课中我们一起学习了Core Data的基础知识。我们创建了一个支持Core Data的iOS项目,定义了包含属性的数据模型实体,并编写代码实现了数据的保存与获取。关键点在于理解托管对象上下文作为我们与数据库交互的主要接口,以及托管对象作为实体实例的角色。通过save()fetchRequest,我们可以轻松地管理应用中的持久化数据,而无需处理复杂的SQL语句。在接下来的教程中,我们将探讨如何更新和删除Core Data中的数据。

005:Core Data数据删除与JSON数据解析

概述

在本节课中,我们将学习两个重要的iOS开发技能:如何使用Core Data删除数据,以及如何从JSON Web服务中解析数据并在表格视图中显示。我们将通过具体的代码示例来演示这两个过程。


Core Data数据删除操作

上一节我们介绍了如何使用Core Data添加和获取数据。本节中,我们来看看如何从Core Data中删除数据。

首先,我们需要创建一个获取请求来找到要删除的数据。

let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "User")

接下来,我们需要获取持久化容器或视图上下文。

let context = persistentContainer.viewContext

为了安全地执行获取操作,我们使用do-catch语句来处理可能出现的错误。

do {
    let results = try context.fetch(fetchRequest)
    if results.count > 0 {
        for object in results {
            if let managedObject = object as? NSManagedObject {
                context.delete(managedObject)
            }
        }
    }
} catch {
    print("获取数据时出错: \(error)")
}

以下是删除操作的关键步骤:

  1. 创建针对特定实体(如"User")的获取请求。
  2. 获取持久化上下文。
  3. 执行获取操作,获取所有匹配的对象。
  4. 遍历结果数组中的每个对象。
  5. 对每个托管对象调用context.delete()方法。

重要提示:删除数据后,必须保存上下文才能使更改永久生效。

do {
    try context.save()
    print("数据删除并保存成功")
} catch {
    print("保存上下文时出错: \(error)")
}

如果不保存上下文,数据实际上并没有从持久化存储中移除,下次获取时仍然会看到这些数据。


JSON数据解析与表格显示

现在我们已经了解了Core Data的数据删除操作,接下来让我们看看如何从JSON Web服务获取数据并在表格视图中显示。

首先,为了避免频繁请求网络服务,我们可以将获取的JSON数据保存到本地文本文件中供开发使用。

创建一个方法来处理从Web服务接收到的JSON数据:

func getData(data: [String: Any]) {
    // 处理接收到的字典数据
}

这个方法接收一个字典类型的参数,因为从JSON解析得到的数据通常是字典格式。

以下是解析JSON数据的关键步骤:

func getData(data: [String: Any]) {
    let dataDict = data
    
    if let geoArray = dataDict["geonames"] as? [[String: Any]] {
        var tableArray = [String]()
        
        for item in geoArray {
            if let cityName = item["toponymName"] as? String {
                tableArray.append(cityName)
            }
        }
        
        // 现在tableArray包含了所有城市名称
        print("获取到的城市: \(tableArray)")
    }
}

让我们详细分析这个过程:

  1. 首先,我们将传入的字典数据赋值给局部变量。
  2. 从字典中提取"geonames"键对应的值,这是一个包含多个字典的数组。
  3. 创建一个可变数组来存储城市名称。
  4. 遍历"geonames"数组中的每个元素。
  5. 从每个元素中提取"toponymName"键对应的字符串值(城市名称)。
  6. 将每个城市名称添加到数组中。

通过这种方式,我们可以从复杂的JSON结构中提取出需要的数据(如城市名称),并将其整理成适合在表格视图中显示的格式。


总结

本节课中我们一起学习了两个重要的iOS开发技能:

  1. Core Data数据删除:我们了解了如何创建获取请求、执行删除操作,以及最重要的是,删除后必须保存上下文才能使更改生效。

  2. JSON数据解析:我们学习了如何从Web服务获取JSON数据,解析复杂的嵌套结构,提取所需信息,并将其转换为适合在表格视图中显示的格式。

这两个技能在实际的iOS应用开发中非常实用,能够帮助你构建功能更完整、用户体验更好的应用程序。记住,处理数据时始终要考虑错误处理和边界情况,确保应用的稳定性和可靠性。

006:在表格视图中展示JSON数据(续) 🚀

在本节课中,我们将继续学习如何从JSON网络服务获取数据,并将其展示在iOS应用的表格视图中。我们将涵盖创建表格视图、设置数据源和代理方法,以及将获取到的数据填充到表格的每个单元格中。


概述 📋

上一节我们介绍了如何发起网络请求并获取JSON数据。本节中,我们来看看如何将这些数据展示在一个表格视图中。我们将创建一个表格视图,设置其约束,并实现必要的数据源方法,以便动态显示从网络服务获取的信息。

创建表格视图 📱

首先,我们需要在故事板中添加一个表格视图。从对象库中拖拽一个表格视图到视图控制器上。

以下是设置表格视图约束的步骤:

  1. 将表格视图的顶部、底部、左侧和右侧约束设置为0,确保它适应不同尺寸的设备。
  2. 为表格视图创建一个原型单元格,并设置其标识符为“cell”。
  3. 将表格视图的delegatedataSource连接到视图控制器。

接下来,我们需要为表格视图创建一个出口(Outlet)。在视图控制器中,添加以下代码:

@IBOutlet weak var myTable: UITableView!

实现表格视图数据源方法 📊

viewDidLoad方法中,设置表格视图的代理和数据源:

override func viewDidLoad() {
    super.viewDidLoad()
    myTable.delegate = self
    myTable.dataSource = self
}

现在,我们需要实现两个必需的表格视图数据源方法:numberOfRowsInSectioncellForRowAt

以下是这两个方法的实现:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return dataArray.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    cell.textLabel?.text = dataArray[indexPath.row]
    return cell
}

numberOfRowsInSection方法中,我们返回数据数组dataArray的元素数量。在cellForRowAt方法中,我们使用标识符“cell”出列一个可重用的单元格,并将数据数组中的相应文本设置为单元格的文本标签。

获取并展示数据 🌐

我们之前已经创建了一个方法来获取网络服务数据。该方法接收一个字典参数,并从字典中提取所需的数据,将其添加到dataArray中。

以下是获取数据并重新加载表格视图的步骤:

  1. 调用获取数据的方法。
  2. 在数据获取成功后,将数据添加到dataArray
  3. 调用myTable.reloadData()方法刷新表格视图。
fetchWebServiceData { dictionary in
    // 从字典中提取数据并添加到 dataArray
    self.dataArray.append(contentsOf: extractedData)
    DispatchQueue.main.async {
        self.myTable.reloadData()
    }
}

运行与测试 🧪

移除所有断点,运行应用。如果网络连接正常,表格视图将成功加载并显示从JSON网络服务获取的数据。

总结 🎯

本节课中,我们一起学习了如何将从JSON网络服务获取的数据展示在表格视图中。我们创建了表格视图,设置了其约束,并实现了必要的数据源方法。通过这种方式,我们可以动态地展示网络数据,使应用内容更加丰富和交互性更强。

在下一节教程中,我们将学习如何从网络服务获取图片,并在集合视图中展示它们。感谢观看,祝您有美好的一天!

007:自动布局与Core Data数据删除

在本节课中,我们将学习两个核心主题:如何使用自动布局创建自适应界面,以及如何在Core Data中删除所有数据对象。我们将从理论讲解开始,然后通过实践项目来巩固理解。

自动布局简介 🎯

上一节我们介绍了Core Data的基本概念,本节中我们来看看如何构建用户界面。自动布局是一个基于约束的布局系统,它允许开发者创建自适应的用户界面。例如,我们希望一个按钮在不同尺寸的iPhone屏幕上都能居中显示。自动布局通过设置约束来实现这一目标,它简化了开发者过去需要为不同屏幕尺寸编写大量代码的工作。

创建项目与界面

首先,我们创建一个新的单视图应用项目,语言选择Swift。在项目创建时,我们暂时不勾选“使用Core Data”选项,因为本节重点在于界面布局。

在故事板中,我们开始设计界面。以下是我们将添加到视图控制器中的组件:

  • 一个标签,用作标题。
  • 两个文本字段,分别用于输入用户名和密码。
  • 三个按钮,分别用于保存、获取和删除数据。

设置自动布局约束

为了让界面元素在不同屏幕尺寸上正确显示,我们需要为它们设置约束。以下是设置约束的关键步骤:

  1. 居中元素:对于需要居中的元素(如标题标签),我们设置“垂直居中”和“水平居中”约束。
  2. 固定尺寸:为元素设置固定的“高度”和“宽度”约束,确保其大小不变。
  3. 相对位置:对于需要固定在某个位置的元素(如顶部的标签),我们设置“顶部间距”、“左侧间距”和“右侧间距”约束,使其与父视图边缘保持固定距离。

设置完成后,我们可以在不同设备尺寸的预览中查看效果,确保布局正确无误。通过自动布局,我们无需编写任何代码即可实现界面的自适应。

Core Data数据删除 🗑️

在上一部分,我们构建了用户界面。现在,我们将学习如何使用Core Data删除所有保存的数据对象。首先,我们需要理解Core Data的几个核心组件。

Core Data核心概念

  • 实体:类似于类,它描述了一个对象的结构。在我们的例子中,我们创建了一个名为“User”的实体。
  • 属性:实体中的属性用于存储数据,其功能类似于Objective-C中的实例变量。我们为“User”实体添加了“name”和“password”两个字符串类型的属性。
  • 托管对象:是实体的具体实例。我们通过NSManagedObject来操作实体中的数据。
  • 持久化存储:默认情况下,Core Data使用SQLite数据库作为后端存储,数据文件位于应用的文档目录中。
  • 上下文:管理对持久化存储的访问。所有数据的增、删、改、查操作都通过NSManagedObjectContext来完成。

实现删除功能

为了演示删除功能,我们需要先完成数据保存和获取的代码。这通常涉及从文本字段获取数据,创建NSManagedObject实例,并通过上下文保存到持久化存储中。

删除所有数据的逻辑如下:

  1. 创建一个获取请求,指定要获取的实体(例如“User”)。
  2. 通过上下文执行该请求,获取所有NSManagedObject对象的数组。
  3. 遍历这个数组,对每个对象调用上下文的delete(_:)方法。
  4. 最后,调用上下文的save()方法将删除操作提交到持久化存储。

核心代码片段如下:

// 假设 context 是 NSManagedObjectContext 实例
let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest(entityName: "User")
do {
    let users = try context.fetch(fetchRequest)
    for user in users {
        context.delete(user)
    }
    try context.save()
    print("所有数据已删除")
} catch {
    print("删除数据时出错: \(error)")
}

通过这段代码,我们可以清空“User”实体中的所有记录。

总结 📝

本节课中我们一起学习了两个重要的iOS开发技能。首先,我们掌握了如何使用自动布局系统来创建能够自适应不同屏幕尺寸的用户界面,这通过设置约束而非硬编码坐标来实现。接着,我们深入探讨了Core Data框架,理解了实体、托管对象和上下文等核心概念,并最终实现了从Core Data中删除所有数据对象的功能。结合界面操作与数据管理,我们能够构建出功能完整的应用程序。

008:适用于纵向布局的自动布局 🧩

在本节课中,我们将学习如何为纵向布局的界面设置自动布局约束。我们将通过一个包含多个控件的例子,演示如何添加和调整约束,以确保界面在不同屏幕尺寸上都能正确显示。


概述

自动布局是iOS开发中用于创建自适应界面的强大工具。它通过定义视图之间的相对关系(约束),而不是固定的坐标和尺寸,来确保界面在各种屏幕尺寸和方向上都能正确布局。本节将重点讲解纵向布局中常用的约束类型及其设置方法。

上一节我们介绍了自动布局的基本概念,本节中我们来看看如何为一个包含多个元素的复杂界面设置约束。


设置单个视图的约束

首先,我们从一个简单的按钮开始。将按钮拖入视图控制器,并为其设置约束。

  1. 选中按钮。
  2. 点击界面右下角的“添加新约束”按钮(或使用菜单)。
  3. 我们需要设置按钮与父视图顶部的垂直间距、左侧(Leading)和右侧(Trailing)的间距。
  4. 同时,可以设置一个固定的高度(Height)和宽度(Width)。

以下是设置约束的步骤描述:

  • 设置垂直间距到顶部布局参考线(Top Layout Guide)。
  • 设置左侧(Leading)和右侧(Trailing)空间到容器边缘。
  • 设置固定的高度和宽度。

设置完成后,可以在预览(Preview)中查看效果。如果按钮位置不正确,可以删除现有约束并重新设置。

所以,这就是设置自动布局的基本方法。


为多个视图设置约束

现在,假设界面中有多个视图。例如,我们有一个图像视图(ImageView)、五个文本输入框(TextField)和一个按钮(Button)。

以下是界面元素的列表:

  • 1个图像视图
  • 5个文本输入框
  • 1个按钮

首先,为按钮设置一个醒目的背景色(例如橙色)和文字颜色(例如黑色)。

接着,为图像视图添加一张图片。可以从桌面或其他位置选择图片并拖入项目的资源目录,然后在图像视图的属性检查器中设置该图片。

现在,我们需要为所有元素设置自动布局约束。

设置图像视图约束

首先设置图像视图的约束。

以下是图像视图的约束设置:

  1. 设置其顶部与父视图顶部的垂直间距。
  2. 设置其左侧(Leading)与容器边缘的间距。
  3. 设置一个固定的高度和宽度。

设置文本输入框约束

接下来,为五个文本输入框设置约束。我们需要确保它们在垂直方向上均匀分布,并且水平方向对齐。

以下是文本输入框的约束设置步骤:

  1. 为第一个文本输入框设置其顶部与图像视图底部的垂直间距。
  2. 设置其左侧(Leading)和右侧(Trailing)与容器边缘的间距。
  3. 为后续的每个文本输入框重复此过程:设置其顶部与前一个视图底部的垂直间距,并设置左右间距。

通过这种方式,所有文本输入框将垂直堆叠并水平对齐。

设置按钮约束

最后,为按钮设置约束。

以下是按钮的约束设置:

  1. 设置其顶部与最后一个文本输入框底部的垂直间距。
  2. 设置其左侧(Leading)和右侧(Trailing)与容器边缘的间距。
  3. 设置一个固定的高度。

调整垂直间距常量

为了使布局更美观,我们可以调整视图之间的垂直间距常量。

以下是调整间距的步骤:

  1. 在文档大纲或画布上选中代表两个视图之间垂直间距的约束线。
  2. 在属性检查器中,将“Constant”值修改为合适的数值,例如30。

现在,运行应用或在预览中查看,界面应该在不同模拟器(如iPhone 4s, 5, 6 Plus)上都能正确显示。


高级约束技巧:对齐与底部固定

我们还可以进行更精细的控制。例如,如果我们希望所有视图的左侧边缘严格对齐,可以为它们设置“Leading”空间到图像视图,而不是容器。

此外,如果我们希望按钮始终固定在屏幕底部,可以修改其约束。

以下是修改按钮到底部的方法:

  1. 删除按钮当前的顶部垂直间距约束。
  2. 为按钮添加一个“垂直间距到底部布局参考线(Bottom Layout Guide)”的约束。
  3. 同时保留其左侧(Leading)和右侧(Trailing)约束,并设置一个固定高度。

如果按钮位置没有立即更新,可以尝试以下操作:

  • 在画布上选择视图控制器。
  • 点击菜单栏中的 “Editor” -> “Resolve Auto Layout Issues” -> “Update Frames”。
  • 或者,在预览中切换到不同设备查看效果,系统可能会提示更新约束。


核心概念总结

本节课的核心是理解几种基本的约束类型及其含义:

  • Leading(左侧)与 Trailing(右侧):定义视图的水平位置,通常相对于父视图或其他视图的边缘。
  • 垂直间距到顶部(Vertical Spacing to Top):定义视图与父视图或上方视图顶部的距离。
  • 垂直间距到底部(Vertical Spacing to Bottom):定义视图与父视图或下方视图底部的距离。

用代码描述一个简单的顶部约束关系(概念上):

// 伪代码,表示“按钮顶部距离父视图顶部20点”
button.topAnchor.constraint(equalTo: superview.topAnchor, constant: 20).isActive = true

动态约束与屏幕适配预览

自动布局的美妙之处在于,无需为不同尺寸的iPhone创建多个故事板或XIB文件。在一个故事板中,通过合理设置约束,就能适配所有屏幕。

为了进行更精确的动态控制(例如,根据不同屏幕尺寸调整按钮高度),我们可以在代码中获取屏幕尺寸。

以下是获取屏幕尺寸的示例代码,写在 viewDidLoad 方法中:

let screenSize = UIScreen.main.bounds
print("Screen Size: \(screenSize)")
let screenWidth = screenSize.width
let screenHeight = screenSize.height
print("Screen Width: \(screenWidth), Screen Height: \(screenHeight)")

通过判断 screenHeight 的值,我们可以得知当前是哪种iPhone型号(例如,iPhone 5/5s高度为568.0,iPhone 6/6s/7/8高度为667.0,iPhone 6+/6s+/7+/8+高度为736.0),从而在代码中动态调整约束常量。这将是下一节课的内容。


总结

本节课中我们一起学习了如何为纵向布局界面设置自动布局。我们从设置单个按钮的约束开始,逐步扩展到包含图像、多个文本输入框和按钮的复杂界面。我们掌握了如何添加垂直间距、左右边距约束,并了解了如何将按钮固定到屏幕底部。最后,我们预览了自动布局在不同屏幕尺寸上的效果,并简要介绍了通过代码获取屏幕尺寸以进行更高级动态适配的思路。掌握这些基础约束是构建自适应iOS界面的关键。

009:使用Core Data与Auto Layout

在本节课中,我们将学习如何结合使用Core Data进行数据持久化,以及如何利用Auto Layout创建动态适配不同屏幕尺寸的用户界面。我们将创建一个简单的用户信息保存与展示应用。

概述

我们将分两部分进行:首先,实现一个将用户输入(姓名和密码)保存到Core Data的功能;其次,创建一个能根据设备屏幕尺寸动态调整布局的标签列表视图。


第一部分:使用Core Data保存数据

上一节我们介绍了项目的基础结构,本节中我们来看看如何将用户界面中的数据保存到Core Data持久化存储中。

1. 获取上下文与创建实体

首先,我们需要获取Core Data的托管对象上下文,它是我们与数据库交互的接口。

let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext

获取上下文后,我们需要创建一个新的实体对象来存储数据。假设我们的实体名为“User”。

let newUser = NSEntityDescription.insertNewObject(forEntityName: “User”, into: context)

2. 为实体设置属性值

创建实体后,我们需要为其属性赋值。这里我们有两个文本框:nameTextFieldpasswordTextField

以下是设置属性值的代码:

newUser.setValue(nameTextField.text, forKey: “name”)
newUser.setValue(passwordTextField.text, forKey: “password”)

3. 保存上下文并重置界面

数据赋值完成后,需要调用上下文的保存方法将数据写入持久化存储。保存成功后,清空文本框以便下次输入。

do {
    try context.save()
    print(“数据保存成功”)
    // 清空输入框
    nameTextField.text = “”
    passwordTextField.text = “”
} catch {
    print(“保存数据时出错: \(error)”)
}

至此,保存功能已经实现。你可以通过设置断点来调试context.save()方法,确认数据是否成功保存。


第二部分:使用Auto Layout实现动态布局

上一部分我们完成了数据的保存,本节中我们来看看如何构建一个能自动适应不同iPhone屏幕尺寸的用户界面。

1. 创建界面元素

我们在故事板中添加五个标签(Label),用于后续展示数据。为了统一管理样式,我们将它们设置为相同的背景色、对齐方式和初始高度。

2. 设置基础约束

以下是设置五个标签布局约束的核心步骤:

首先,为第一个标签(Label1)设置约束:

  • 垂直间距:贴紧容器顶部。
  • 水平间距:对齐容器左右边距。
  • 固定高度:例如50点。

然后,为后续的标签(Label2到Label5)设置约束。关键在于将它们与上一个标签建立联系,实现连锁反应。

以下是设置Label2约束的逻辑:

  • 垂直间距:位于Label1下方。
  • 水平对齐:其左侧(Leading)与Label1的左侧对齐,右侧(Trailing)与Label1的右侧对齐。
  • 等尺寸:其高度(Height)和宽度(Width)与Label1相等。

对Label3、Label4、Label5重复此过程,每个标签都基于上一个标签进行约束。这样,只要修改Label1的尺寸,所有标签的尺寸都会同步改变。

3. 创建出口并编写动态调整代码

为了能通过代码动态调整标签高度,我们需要为Label1的高度约束创建一个出口(IBOutlet)。

@IBOutlet weak var commonLabelHeightConstraint: NSLayoutConstraint!

然后,我们创建一个函数(例如 adjustLayoutForScreenSize),根据不同的屏幕尺寸来更新这个公共高度约束的值。

func adjustLayoutForScreenSize() {
    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height

    if screenWidth == 320.0 && screenHeight == 568.0 {
        // iPhone 5/5S/SE 尺寸
        commonLabelHeightConstraint.constant = 70
    } else if screenWidth == 375.0 && screenHeight == 667.0 {
        // iPhone 6/6S/7/8 尺寸
        commonLabelHeightConstraint.constant = 60
    } else if screenWidth == 414.0 && screenHeight == 736.0 {
        // iPhone 6+/6S+/7+/8+ 尺寸
        commonLabelHeightConstraint.constant = 55
    } else {
        // 其他尺寸,如iPhone X及以上,设置一个默认值
        commonLabelHeightConstraint.constant = 50
    }
    // 更新视图布局
    self.view.layoutIfNeeded()
}

viewDidLoad 方法中调用此函数,应用启动时就会根据当前设备调整布局。

4. Auto Layout的优势

通过上述方法,我们实现了:

  • 代码精简:只需控制一个约束,即可影响所有关联视图。
  • 灵活适配:轻松应对多种屏幕尺寸,无需为每种设备编写大量独立布局代码。
  • 维护方便:UI调整只需修改少数约束或条件判断逻辑。

你可以将此模式扩展到其他控件,如图片视图(ImageView)、按钮(Button)等,构建出复杂且自适应的用户界面。


总结

本节课中我们一起学习了两个iOS开发的核心技能:

  1. Core Data操作:我们掌握了如何获取托管对象上下文、创建实体、设置属性以及保存数据,实现了用户信息的持久化存储。
  2. 动态Auto Layout:我们通过建立视图间的连锁约束,并配合代码动态修改约束常量,创建了一个能够智能适配不同iPhone屏幕尺寸的UI布局。

结合使用这些技术,你可以开发出数据驱动、界面美观且适配性强的iOS应用程序。

010:表格视图单元格中的集合视图简介 📱

在本节课中,我们将学习如何在表格视图的单元格内嵌入并显示一个集合视图。这是一种常见的界面设计模式,例如用于展示图片画廊或产品列表。我们将结合之前学习的表格视图和集合视图知识,创建一个复合视图。

项目创建与界面搭建

首先,我们创建一个新的Xcode项目,并将其命名为“Combination”。

在项目创建后,我们进入主故事板文件。从对象库中,将一个表格视图拖拽到视图控制器上。

为了让表格视图填满整个屏幕,我们需要为其设置约束。选中表格视图,点击右下角的约束按钮,设置其与容器视图的前导尾随顶部底部空间均为0。

接下来,我们需要为表格视图配置一个原型单元格。在表格视图的属性面板中,将原型单元格的数量设置为1,并调整其高度。

然后,我们为这个原型单元格设置一个重用标识符,例如“cell”。

现在,关键的一步来了:我们要在这个表格视图单元格内部添加一个集合视图。再次从对象库中,将一个集合视图拖拽到刚才的表格视图单元格上。

调整集合视图的大小,使其适应单元格。同样,我们需要为这个集合视图单元格设置一个重用标识符,例如“CollectionCell”。

在集合视图单元格内部,我们添加一个图像视图,用于后续显示图片。

建立连接与创建类文件

界面搭建完成后,我们需要建立代码与界面元素的连接。

首先,在视图控制器中,为表格视图创建一个出口连接,命名为tableView。同时,将表格视图的delegatedataSource属性设置为这个视图控制器。

由于集合视图是内嵌在表格视图单元格中的,我们需要为这个自定义的单元格创建一个单独的类。新建一个Cocoa Touch Class文件,将其命名为CustomTableViewCell,并使其继承自UITableViewCell

回到故事板,选中表格视图的原型单元格,在身份检查器中,将其类设置为CustomTableViewCell

然后,在CustomTableViewCell类中,为单元格内的集合视图创建一个出口连接,命名为collectionView

准备数据与实现集合视图协议

为了在集合视图中显示内容,我们需要准备一些图片资源。这里我们使用一组国家旗帜的图片,并将它们的文件名存储在一个数组中。

CustomTableViewCell类中,我们定义一个图片名称数组:

let imageArr = ["Brazil.jpg", "China.jpg", "France.jpg", "Germany.jpg", "India.jpg", "Russia.jpg", "Spain.jpg", "US.jpg", "UK.jpg"]

接下来,我们需要让CustomTableViewCell类遵循集合视图的协议,并实现必要的方法。在类声明中添加UICollectionViewDelegateUICollectionViewDataSource

awakeFromNib方法中,设置集合视图的代理和数据源:

override func awakeFromNib() {
    super.awakeFromNib()
    collectionView.delegate = self
    collectionView.dataSource = self
}

然后,实现集合视图数据源的两个核心方法:

  1. numberOfItemsInSection:返回数组imageArr的元素数量。
  2. cellForItemAt:出列一个标识符为“CollectionCell”的集合视图单元格,并根据索引路径设置其图像视图的图片。

为了能在cellForItemAt方法中访问集合视图单元格内的图像视图,我们需要为它创建一个类。新建一个UICollectionViewCell的子类,例如CollectionViewCell,并在其中为图像视图创建出口连接imgView

回到故事板,将集合视图原型单元格的类设置为CollectionViewCell

现在,我们可以在CustomTableViewCellcellForItemAt方法中,安全地配置每个集合视图单元格了。

实现表格视图协议

上一节我们完成了单元格内部集合视图的配置,现在回到主视图控制器,实现表格视图的协议。

首先,确保视图控制器类声明中遵循了UITableViewDelegateUITableViewDataSource协议。

viewDidLoad方法中,设置表格视图的代理和数据源:

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.delegate = self
    tableView.dataSource = self
}

然后,实现表格视图数据源方法:

  1. numberOfSections:返回1,表示只有一个分区。
  2. numberOfRowsInSection:返回一个数字,例如5,表示表格有5行。
  3. cellForRowAt:出列一个标识符为“cell”的表格视图单元格(即我们的CustomTableViewCell),并返回它。

由于集合视图的内容已经在CustomTableViewCell内部配置好,这里我们不需要对单元格做额外设置。表格的行高可以通过heightForRowAt代理方法设置,这里我们可以返回一个固定值,例如200。

运行与总结

至此,所有代码部分已完成。现在可以运行应用程序,查看最终效果。你应该能看到一个表格,每一行内部都包含一个水平滚动的集合视图,展示不同的国家旗帜图片。

本节课中,我们一起学习了如何将集合视图嵌入到表格视图的单元格中。关键步骤包括:

  1. 在故事板中搭建嵌套的视图层次结构。
  2. 为自定义的表格视图单元格和集合视图单元格创建独立的类文件并建立连接。
  3. 在自定义单元格类中实现集合视图的协议来管理内部内容。
  4. 在主视图控制器中实现表格视图的协议来管理外部行。

这种组合视图的技术非常实用,可以帮你构建出信息丰富且布局灵活的iOS应用界面。

011:在TableView中嵌入CollectionView 📱

概述

在本节课中,我们将学习如何在UITableView的单元格内嵌入一个UICollectionView。这是一种常见的iOS界面设计模式,用于创建可垂直滚动的列表,其中每个列表项内部又包含一个可水平滚动的图片集。我们将通过修改数据源、调整滚动方向以及设置自动布局来完成这个功能。


创建多个分区

上一节我们设置了基础的TableView和CollectionView。本节中,我们来看看如何为TableView创建多个分区,以展示更多内容。

在视图控制器中,我们需要实现numberOfSections(in:)方法。以下代码将TableView的分区数量设置为5:

func numberOfSections(in tableView: UITableView) -> Int {
    return 5
}

执行此操作后,TableView将包含5个独立的分区。


调整CollectionView的滚动方向

目前,CollectionView是垂直滚动的。为了让每个分区内的图片可以水平滑动浏览,我们需要修改它的滚动方向。

在Storyboard中,按以下步骤操作:

  1. 选中CollectionView。
  2. 在属性检查器中,找到“Scroll Direction”选项。
  3. 将“Vertical”改为“Horizontal”。


设置单元格背景色

为了更好地区分CollectionView的单元格,我们可以为其设置背景颜色。

在自定义的CollectionViewCell类中,我们可以通过cellForItemAt数据源方法设置背景色。例如,将背景色设置为浅灰色:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCellIdentifier", for: indexPath) as! YourCustomCell
    cell.backgroundColor = UIColor.lightGray
    // ... 其他配置代码
    return cell
}


运行与测试

完成以上步骤后,运行应用程序。现在你应该能看到一个包含5个分区的TableView。每个分区内都有一个CollectionView,可以水平滚动查看多张图片,而整个列表则可以垂直滚动。

如果增加numberOfSections(in:)方法的返回值(例如改为9),TableView将显示更多的分区。


添加自动布局约束

为了确保界面在不同尺寸的设备上都能正确显示,我们需要为CollectionView添加自动布局约束。

以下是需要添加的约束:

  • Leading(左对齐): 与TableView单元格的左边缘对齐。
  • Trailing(右对齐): 与TableView单元格的右边缘对齐。
  • Top(顶部对齐): 与TableView单元格的顶部对齐。
  • Bottom(底部对齐): 与TableView单元格的底部对齐。

这些约束确保了CollectionView会跟随其所在的TableView单元格的大小变化而调整自身大小。


实现原理总结

本节课中我们一起学习了组合使用TableView和CollectionView的方法。让我们回顾一下整个实现的层次结构和关键代码:

  1. 界面层次: 在ViewController上放置一个TableView。在TableView的Cell中,嵌入一个CollectionView。最后,在CollectionView的Cell中放置用于显示图片的ImageView。
  2. TableView数据源: 在ViewController中,实现了tableView(_:numberOfRowsInSection:)tableView(_:cellForRowAt:)方法来配置TableView。
  3. CollectionView数据源: 在自定义的TableViewCell类中:
    • 创建了一个IBOutlet来连接Storyboard中的CollectionView。
    • 定义了一个图片数组作为数据源。
    • 设置CollectionView的委托和数据源为自己。
    • 实现了collectionView(_:cellForItemAt:)方法,在其中出列单元格、设置图片和背景色,并返回配置好的单元格。

核心关系可以概括为:ViewController 管理 TableView -> TableViewCell 内包含并管理 CollectionView -> CollectionViewCell 显示最终内容(如图片)


总结

本节课中,我们深入探讨了如何在UITableView中嵌套UICollectionView来创建复杂的滚动界面。我们完成了创建多个TableView分区、将CollectionView的滚动方向改为水平、设置单元格样式以及添加自动布局约束等关键步骤。掌握这种组合视图的技术,能够极大地丰富你应用的界面表现力和用户体验。

012:相机、照片库与图像视图 📸

在本节课中,我们将学习如何从设备的相机或照片库中获取图片,并将其显示在应用的图像视图(UIImageView)中。整个过程涉及创建图像选择器控制器、处理用户授权以及实现必要的代理方法。


创建图像选择器控制器

首先,我们需要创建一个图像选择器控制器(UIImagePickerController)的实例。这个控制器负责管理从相机或照片库选择媒体的界面。

以下是创建和配置图像选择器控制器的步骤:

  1. 初始化选择器:创建一个 UIImagePickerController 的实例。
  2. 设置来源类型:指定图片来源是相机(.camera)还是照片库(.photoLibrary)。
  3. 设置代理:将当前视图控制器设置为选择器的代理,以便接收用户操作的结果。
  4. 模态呈现:将选择器控制器以模态方式呈现给用户。

let imagePicker = UIImagePickerController()
imagePicker.sourceType = .photoLibrary // 或 .camera
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)


实现代理方法

图像选择器控制器通过代理方法将用户的选择结果返回给我们的应用。我们需要实现两个核心的代理方法。

以下是必须实现的 UIImagePickerControllerDelegate 方法:

  • imagePickerController(_:didFinishPickingMediaWithInfo:):当用户成功选择一张图片(或视频)时调用。我们需要从这个方法中获取选中的图片。
  • imagePickerControllerDidCancel(_:):当用户取消选择操作时调用。我们需要在这个方法中关闭选择器界面。
// 处理选中的媒体
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    // 从 info 字典中获取原始图片
    if let selectedImage = info[.originalImage] as? UIImage {
        // 将图片设置到图像视图
        myImageView.image = selectedImage
        // 设置图像视图的内容模式为等比例适应
        myImageView.contentMode = .scaleAspectFit
    }
    // 关闭选择器
    picker.dismiss(animated: true, completion: nil)
}

// 处理取消操作
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    // 关闭选择器
    picker.dismiss(animated: true, completion: nil)
}

配置图像视图

在成功获取图片后,我们需要将其显示在用户界面上。这通常通过一个 UIImageView 组件来完成。

配置图像视图的关键点如下:

  • 设置图片:将从代理方法中获取的 UIImage 对象赋值给图像视图的 image 属性。
  • 调整显示模式:将图像视图的 contentMode 属性设置为 .scaleAspectFit,这可以确保图片在不失真的情况下适应视图的边界。

myImageView.image = selectedImage
myImageView.contentMode = .scaleAspectFit

请求用户权限

在访问设备的相机或照片库之前,应用必须获得用户的明确许可。这需要在 Info.plist 文件中添加相应的权限描述。

以下是需要在 Info.plist 中添加的键值对:

  • 访问相机:键为 NSCameraUsageDescription,值为描述用途的字符串,例如“此应用需要使用相机来拍摄照片”。
  • 访问照片库:键为 NSPhotoLibraryUsageDescription,值为描述用途的字符串,例如“此应用需要访问您的照片库来选择图片”。

当用户首次尝试使用相关功能时,系统会自动弹出授权对话框。用户必须点击“允许”,应用才能正常使用相机或照片库。


运行与测试

完成以上所有步骤后,我们可以运行应用进行测试。

测试流程如下:

  1. 点击触发按钮,调用图像选择器。
  2. 首次使用时,系统会请求访问照片库(或相机)的权限,请点击“允许”。
  3. 在照片库中选择一张图片。
  4. 观察图片是否正确显示在应用的图像视图中。图片可能不会填满整个视图,这是由 .scaleAspectFit 模式决定的,目的是保持图片比例。

如果选择相机作为来源,在真实设备上运行时,点击按钮会直接打开相机界面。


总结

本节课中我们一起学习了如何集成 iOS 设备的媒体选择功能。我们掌握了创建和配置 UIImagePickerController 的方法,实现了处理选择结果和取消操作的代理方法,学会了将获取的图片显示在 UIImageView 中,并了解了为访问隐私敏感功能(相机和照片库)配置应用权限的必要步骤。通过本课的知识,你可以为应用轻松添加从相册选图或拍照上传的功能。

013:应用委托与网络请求基础

概述

在本节课中,我们将学习iOS应用开发中的两个核心概念:应用委托(App Delegate)网络请求基础。应用委托负责管理应用的生命周期,而网络请求则是从服务器获取数据的关键技术。我们将分别探讨这两个主题,帮助你理解它们的工作原理和基本用法。


应用委托:13.1:应用生命周期详解 🌀

上一节我们介绍了课程的整体结构,本节中我们来看看iOS应用的核心管理者——应用委托。

应用委托与应用程序对象协同工作,确保你的应用能与系统及其他应用正确交互。它的核心职责是处理应用的整个生命周期。

一个iOS应用在其生命周期中会经历五种不同的状态:

以下是应用的五种状态:

  1. 未运行(Not Running):应用尚未启动,或已被用户或系统终止。
  2. 未激活(Inactive):应用在前台运行,但未接收事件(例如,应用启动后、切换到其他应用前的短暂瞬间)。
  3. 激活(Active):应用在前台运行并正常接收事件。这是前台应用的常规模式。
  4. 后台(Background):应用在后台执行代码,但屏幕不可见(例如,正在下载内容)。用户退出应用时,系统会先将应用移至后台状态,再将其挂起。
  5. 挂起(Suspended):应用停留在内存中,但不再执行任何代码。

为了响应应用在不同状态间的转换,应用委托提供了一系列方法。

以下是应用委托的关键方法及其调用时机:

  • application(_:willFinishLaunchingWithOptions:):应用启动后、主故事板加载完成时调用。此时界面已加载,但应用状态尚未恢复。你可以在此进行初始化工作。
  • application(_:didFinishLaunchingWithOptions:):在 willFinishLaunchingWithOptions 之后、应用状态恢复后调用。它告知你启动过程基本完成,应用即将启动,你仍有最后机会进行一些调整。
  • applicationDidBecomeActive(_:):当应用从“未激活”状态进入“激活”状态时调用。例如,应用启动完成,或用户接完电话后返回应用。
  • applicationWillResignActive(_:):当应用即将从“激活”状态进入“未激活”状态时调用。这通常发生在有临时中断时,如来电、收到短信,或用户开始将应用切换到后台。
  • applicationDidEnterBackground(_:):应用进入后台时调用。你可以在此释放共享资源或保存用户数据。
  • applicationWillEnterForeground(_:):应用即将从后台进入前台时调用。
  • applicationWillTerminate(_:):应用即将终止时调用。这是你保存数据的最后机会。

典型流程示例:用户启动应用时,会依次调用 willFinishLaunching -> didFinishLaunching -> didBecomeActive。如果此时有来电,则会调用 willResignActive -> didEnterBackground。通话结束后,调用 willEnterForeground -> didBecomeActive。最后用户关闭应用时,会调用 willTerminate

理解应用委托和生命周期对于应对面试和开发健壮的应用至关重要。


网络请求:13.2:使用URLSession获取数据 🌐

上一节我们深入了解了应用的生命周期管理,本节中我们将转向另一个基础技能:如何从网络服务(Web Service)获取数据。

我们将学习如何使用 URLSession 发起一个简单的HTTP GET请求,并解析返回的JSON数据。

首先,需要创建一个URL请求。以下是创建请求的基本代码:

let url = URL(string: "https://api.example.com/data")!
var request = URLRequest(url: url)
request.httpMethod = "GET"

接下来,使用 URLSession 创建一个数据任务来执行这个请求,并在闭包中处理响应。

以下是执行网络请求和处理响应的步骤:

  1. 使用 URLSession.shared.dataTask 方法创建任务。
  2. 在完成处理闭包中,检查错误(error)和响应数据(data)。
  3. 将接收到的二进制数据(Data)转换为字符串,以便初步查看。
  4. 使用 JSONSerialization 将数据转换为Swift可用的对象(如字典或数组)。

核心的网络请求代码如下:

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    // 检查是否有错误
    if let error = error {
        print("请求错误: \(error.localizedDescription)")
        return
    }
    
    // 确保收到了数据
    guard let data = data else {
        print("未收到数据")
        return
    }
    
    // 将数据转换为字符串并打印(用于调试)
    if let responseString = String(data: data, encoding: .utf8) {
        print("原始响应字符串: \(responseString)")
    }
    
    // 尝试将JSON数据解析为对象
    do {
        if let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
            print("解析后的JSON对象: \(jsonObject)")
            // 后续可以在这里根据键名提取具体数据
        }
    } catch {
        print("JSON解析错误: \(error)")
    }
}
task.resume() // 不要忘记启动任务

重要配置:为了允许HTTP请求(而非安全的HTTPS),你需要在项目的 Info.plist 文件中添加一个例外。添加 App Transport Security Settings 字典,并在其下添加一个布尔键 Allow Arbitrary Loads,将其值设置为 YES请注意,这仅适用于开发测试,上架App Store前应移除或配置更安全的ATS规则。

运行应用并触发网络请求后,你将在控制台看到从服务器获取的原始字符串和解析后的JSON对象。通常,JSON数据是嵌套的字典和数组结构。在后续教程中,我们将学习如何从中提取特定字段(如“name”),并将其显示在表格视图(UITableView)中。


总结

本节课中我们一起学习了iOS开发的两个重要基础。
首先,我们详细探讨了应用委托(App Delegate),它是应用生命周期的管理者,定义了应用从启动到终止的各个状态(未运行、未激活、激活、后台、挂起)以及状态转换时调用的对应方法。
其次,我们介绍了如何使用 URLSession 发起基本的网络GET请求,获取JSON格式的数据,并通过 JSONSerialization 进行初步解析。理解这些概念是构建功能完整、交互流畅的iOS应用的基石。在接下来的课程中,我们将学习如何利用获取的数据来填充用户界面。

014:条件语句与函数

在本章中,我们将学习 Swift 编程中的两个核心概念:条件语句函数。条件语句(如 ifelseswitch)用于根据不同的条件执行不同的代码块。函数则是一段可重复使用的代码,用于执行特定任务。掌握这些概念是构建复杂 iOS 应用的基础。

第 2.1 节:ifelse 语句

上一节我们介绍了变量和数据类型。本节中,我们来看看如何使用 ifelse 语句来控制程序的执行流程。

if 语句是一种条件判断语句,它根据一个条件是否为真来决定是否执行其内部的代码块。其基本结构如下:

if 条件 {
    // 如果条件为真,则执行这里的代码
}

例如,我们创建一个变量 lives 并赋值为 4:

var lives = 4

现在,如果我们想检查 lives 是否等于 10,可以这样写:

if lives == 10 {
    print(“Hello 10”)
}

请注意,这里使用了双等号 ==。它与单等号 = 有重要区别:

  • 单等号 =:用于赋值,例如 var lives = 4 是将值 4 赋给变量 lives
  • 双等号 ==:用于比较,例如 lives == 10 是判断变量 lives 的值是否等于 10

如果条件不满足,我们可能希望执行另一段代码。这时就需要 else 语句。

if lives == 6 {
    print(“Value is 6”)
} else {
    print(“Value is not 6”)
}

当需要检查多个条件时,可以使用 else if

以下是 ifelse ifelse 组合使用的示例:

if lives == 5 {
    print(“Hello 5”)
} else if lives == 6 {
    print(“Hello 6”)
} else if lives == 7 {
    print(“Hello 7”)
} else if lives == 8 {
    print(“Hello 8”)
} else if lives == 9 {
    print(“Hello 9”)
} else {
    print(“Hello 10”)
}

程序会从上到下依次检查每个条件,一旦某个条件为真,就会执行对应的代码块,然后跳过其余检查。

第 2.2 节:逻辑运算符

if 语句中,我们经常需要组合多个条件。这时就需要用到逻辑运算符。

最常见的两种逻辑运算符是 与(&&或(||

  • 与运算符 &&:要求所有条件都为真,整个表达式才为真。
  • 或运算符 ||:要求至少一个条件为真,整个表达式就为真。

让我们通过例子来理解。假设 lives 的值是 11。

使用 &&(与)的示例:

if lives > 10 && lives < 15 {
    print(“Success: lives is between 10 and 15”)
}

因为 lives > 10 为真,并且 lives < 15 也为真,所以整个条件为真,会打印 “Success”。

使用 ||(或)的示例:

if lives > 20 || lives == 11 {
    print(“Success: lives is either greater than 20 OR equal to 11”)
}

虽然 lives > 20 为假,但 lives == 11 为真。因为至少有一个条件为真,所以整个条件为真,会打印 “Success”。

第 2.3 节:switch 语句

当我们需要基于同一个变量的多种可能值执行不同操作时,使用多个 else if 会显得冗长。switch 语句提供了更清晰、更简洁的写法。

switch 语句将一个值与多个可能的模式进行比较,然后执行第一个匹配的模式所对应的代码块。

其基本结构如下:

switch 要判断的值 {
case 值1:
    // 匹配值1时执行的代码
case 值2:
    // 匹配值2时执行的代码
default:
    // 所有case都不匹配时执行的代码
}

让我们看一个例子。假设我们有一个变量 highScore

var highScore = 8

使用 switch 语句来根据分数输出不同信息:

switch highScore {
case 0:
    print(“Score is zero”)
case 1:
    print(“Hello case 1”)
case 2:
    print(“Hello case 2”)
case 3:
    print(“Hello case 3”)
case 4:
    print(“Hello case 4”)
case 5:
    print(“Hello case 5”)
case 6:
    print(“Hello case 6”)
case 7:
    print(“Hello case 7”)
case 8:
    print(“Hello case 8”) // 因为 highScore 是 8,所以会执行这一行
case 9:
    print(“Hello case 9”)
default:
    print(“No match found”)
}

与一系列 if-else if 语句相比,switch 的代码结构更整齐,也更易于阅读和维护。

第 2.4 节:函数基础

前面我们学习了变量和条件逻辑。现在,我们来看看如何将这些代码组织成可重用的单元——函数

函数是一段完成特定任务的独立代码块。通过给函数起一个名字,我们可以在需要时多次“调用”它,而无需重复编写相同的代码。

定义一个函数使用 func 关键字。一个最简单的函数如下:

func sayHello() {
    print(“Hello”)
}

要执行这个函数里的代码,需要调用它:

sayHello() // 输出:Hello

第 2.5 节:带参数的函数

函数可以接收输入值,这些输入值称为参数。参数让函数变得更加灵活和强大。

定义一个带参数的函数:

func helloUser(name: String) {
    print(“Hello \(name)”)
}

在这个函数中,name 是一个类型为 String 的参数。调用时,我们必须提供一个字符串:

helloUser(name: “Tisha”) // 输出:Hello Tisha

函数也可以有多个参数。以下是带有两个参数的函数示例:

func playerDetails(name: String, age: Int) {
    print(“My name is \(name) and my age is \(age).”)
}

调用这个函数时,需要按顺序提供两个参数:

playerDetails(name: “Tisha”, age: 24) // 输出:My name is Tisha and my age is 24.

通过使用参数,我们可以用同一个函数处理不同的数据。例如,在创建注册表单时,我们可以编写一个函数来验证用户输入的用户名、密码、邮箱等信息,然后在需要验证的任何地方调用这个函数。


本章总结

在本章中,我们一起学习了 Swift 中控制程序流和代码组织的核心工具。

  1. 条件语句:我们掌握了 ifelse ifelse 语句,用于基于不同条件执行不同代码。同时,我们学习了逻辑运算符 &&(与)和 ||(或)来组合多个条件。
  2. switch 语句:我们了解了如何使用 switch 语句来清晰地处理一个变量对应多种可能值的情况,这比使用多个 else if 更简洁。
  3. 函数:我们学习了如何定义和调用函数。函数通过将代码封装成可重用的块,极大地提高了代码的整洁性和可维护性。我们还学会了如何定义带参数的函数,使其能够接收外部输入并执行特定任务。

结合第一章的变量知识,你现在已经掌握了编写具有基本逻辑和结构的小程序所需的核心技能。在接下来的章节中,我们将利用这些基础来探索更复杂的 iOS 开发概念。

015:中级iOS开发教程

在本教程中,我们将学习Swift编程语言中的几个核心概念,包括函数、变量、数组、字典和集合。这些是构建iOS应用程序的基础。我们将从简单的概念开始,逐步深入到更复杂的数据结构。

章节1:函数

上一节我们介绍了教程的概述,本节中我们来看看Swift中的函数。函数是一段执行特定任务的代码块,可以接受输入参数并返回结果。

创建与调用函数

以下是创建一个简单函数的方法:

func greet() {
    print("Hello, World!")
}
greet() // 调用函数

带参数的函数

函数可以接受多个参数。以下是创建一个接受多个参数的函数的方法:

func details(name: String, age: Int, hobby: String, dream: String) {
    print("My name is \(name).")
    print("My age is \(age).")
    print("My hobby is \(hobby).")
    print("I want to become a \(dream).")
}
details(name: "John", age: 24, hobby: "coding", dream: "software engineer")

带返回值的函数

函数可以返回一个值。以下是创建一个返回整数的函数的方法:

func addIntegers(number1: Int, number2: Int) -> Int {
    let sum = number1 + number2
    return sum
}
let result = addIntegers(number1: 10, number2: 20)
print(result) // 输出 30

函数的作用域

变量的作用域决定了它在代码中的可访问性。在函数内部声明的变量只能在该函数内部访问。

func abc() {
    let myVariable = 24 // 此变量仅在函数内部可访问
}
// print(myVariable) // 这里会报错,因为myVariable在函数外部不可访问

let globalVariable = 24 // 此变量在全局范围内可访问
func xyz() {
    print(globalVariable) // 可以访问全局变量
}
xyz()

章节2:变量与数据类型

上一节我们介绍了函数,本节中我们来看看Swift中的变量和基本数据类型。变量用于存储数据,是编程的基础。

整数

整数用于存储没有小数点的数字。

var score: Int = 10
score += 5 // score 现在是 15
score -= 2 // score 现在是 13
score *= 2 // score 现在是 26
score /= 2 // score 现在是 13

双精度浮点数

双精度浮点数用于存储带小数点的数字,提供比单精度浮点数更精确的结果。

var myDouble: Double = 10.2
myDouble += 3.6 // myDouble 现在是 13.8
myDouble -= 3.6 // myDouble 现在是 10.2
myDouble *= 2.0 // myDouble 现在是 20.4

字符串

字符串是字符的集合,用于存储文本。

var myString: String = "Hello, "
let name: String = "Matt"
myString += name // myString 现在是 "Hello, Matt"
print(myString)

布尔值

布尔值表示真或假,用于逻辑判断。

var isTrue: Bool = true
var isFalse: Bool = false

元组

元组允许你将多个值组合成一个复合值。

var myTuple = (x: 16, y: 20)
print(myTuple.x) // 输出 16
print(myTuple.y) // 输出 20

letvar 的区别

let 用于声明常量,其值不可改变;var 用于声明变量,其值可以改变。

let constantValue: Int = 20 // 常量,不可更改
var variableValue: Int = 10 // 变量,可以更改
variableValue = 30 // 正确
// constantValue = 40 // 错误:无法更改常量的值

类型转换

有时需要将一种数据类型转换为另一种。

var myInt: Int = 10
var myDoubleForConversion: Double = 20.3
// 将Double转换为Int
var sumInt = myInt + Int(myDoubleForConversion) // 结果是 30
// 将Int转换为Double
var sumDouble = Double(myInt) + myDoubleForConversion // 结果是 30.3

章节3:数组

上一节我们介绍了变量,本节中我们来看看Swift中的数组。数组是存储相同数据类型元素的有序集合。

创建与访问数组

以下是创建和访问数组的方法:

var playerNames: [String] = ["Rohan", "Mohan", "Sohan"]
print(playerNames[0]) // 输出 "Rohan"
print(playerNames[1]) // 输出 "Mohan"

数组的常用操作

数组提供了多种方法来操作其中的元素。

以下是数组的一些常用操作:

// 获取元素数量
print(playerNames.count)

// 添加元素
playerNames.append("Tushar")

// 在指定索引插入元素
playerNames.insert("Lama", at: 0)

// 移除指定索引的元素
playerNames.remove(at: 0)

// 移除第一个元素
playerNames.removeFirst()

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/educba-swift-mid-iosdev/img/5ce228af12a1a9c7a3031a7d1d4650a3_9.png)

// 移除最后一个元素
playerNames.removeLast()

// 排序
playerNames.sort()
print(playerNames)

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/educba-swift-mid-iosdev/img/5ce228af12a1a9c7a3031a7d1d4650a3_11.png)

// 检查是否包含某元素
print(playerNames.contains("Tushar")) // 输出 true 或 false

章节4:字典

上一节我们介绍了数组,本节中我们来看看Swift中的字典。字典以键值对的形式存储数据,允许你通过唯一的键来检索值。

创建与访问字典

以下是创建和访问字典的方法:

var dictionary: [String: Int] = ["Mohan": 20, "Sohan": 30, "Rohan": 40]
print(dictionary["Mohan"]) // 输出 20

字典的常用操作

字典提供了多种方法来操作键值对。

以下是字典的一些常用操作:

// 获取键值对数量
print(dictionary.count)

// 更新值
dictionary["Mohan"] = 50
// 或使用 updateValue 方法
dictionary.updateValue(60, forKey: "Tushar")

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/educba-swift-mid-iosdev/img/5ce228af12a1a9c7a3031a7d1d4650a3_13.png)

// 移除键值对
dictionary.removeValue(forKey: "Tushar")

章节5:集合

上一节我们介绍了字典,本节中我们来看看Swift中的集合。集合存储相同数据类型且无序、不重复的值。

创建与操作集合

以下是创建和操作集合的方法:

var mySet: Set<String> = ["Rohan", "Mohan", "Sohan"]
print(mySet) // 顺序可能不同

// 插入元素
mySet.insert("Tushar")
// 尝试插入重复元素
let inserted = mySet.insert("Rohan") // inserted 为 false

// 移除元素
mySet.remove("Tushar")

// 检查元素是否存在
print(mySet.contains("Mohan")) // 输出 true

// 获取元素数量
print(mySet.count)

集合的集合操作

集合支持并集、交集和差集等数学运算。

以下是集合的集合操作示例:

let set1: Set<Int> = [0, 1, 2, 3]
let set2: Set<Int> = [0, 2, 4, 6]

// 并集
let unionSet = set1.union(set2) // 结果: [0, 1, 2, 3, 4, 6] (顺序不定)

// 交集
let intersectionSet = set1.intersection(set2) // 结果: [0, 2] (顺序不定)

// 差集
let subtractingSet = set1.subtracting(set2) // 结果: [1, 3] (顺序不定)

总结

在本教程中,我们一起学习了Swift编程语言的几个核心特性。我们首先了解了如何定义和调用函数,包括带参数和返回值的函数,以及函数作用域的概念。接着,我们探讨了不同的变量类型:整数、双精度浮点数、字符串、布尔值和元组,并比较了letvar的区别,以及如何进行类型转换。然后,我们研究了三种重要的集合类型:数组用于有序存储相同类型的元素;字典用于通过键来存储和检索值;集合用于存储无序且唯一的元素,并支持并集、交集和差集操作。掌握这些基础知识是进行有效Swift和iOS开发的关键。

posted @ 2026-03-29 09:13  绝不原创的飞龙  阅读(5)  评论(0)    收藏  举报