- Swift 教程
- Swift - 首页
- Swift - 概述
- Swift - 环境
- Swift - 基本语法
- Swift - 变量
- Swift - 常量
- Swift - 字面量
- Swift - 注释
- Swift 运算符
- Swift - 运算符
- Swift - 算术运算符
- Swift - 比较运算符
- Swift - 逻辑运算符
- Swift - 赋值运算符
- Swift - 位运算符
- Swift - 其他运算符
- Swift 高级运算符
- Swift - 运算符重载
- Swift - 算术溢出运算符
- Swift - 恒等运算符
- Swift - 范围运算符
- Swift 数据类型
- Swift - 数据类型
- Swift - 整数
- Swift - 浮点数
- Swift - Double
- Swift - 布尔值
- Swift - 字符串
- Swift - 字符
- Swift - 类型别名
- Swift - 可选类型
- Swift - 元组
- Swift - 断言和前提条件
- Swift 控制流
- Swift - 决策控制
- Swift - if 语句
- Swift - if...else if...else 语句
- Swift - if-else 语句
- Swift - 嵌套 if 语句
- Swift - switch 语句
- Swift - 循环
- Swift - for in 循环
- Swift - while 循环
- Swift - repeat...while 循环
- Swift - continue 语句
- Swift - break 语句
- Swift - fall through 语句
- Swift 集合
- Swift - 数组
- Swift - 集合
- Swift - 字典
- Swift 函数
- Swift - 函数
- Swift - 嵌套函数
- Swift - 函数重载
- Swift - 递归
- Swift - 高阶函数
- Swift 闭包
- Swift - 闭包
- Swift - 逃逸和非逃逸闭包
- Swift - 自动闭包
- Swift 面向对象编程
- Swift - 枚举
- Swift - 结构体
- Swift - 类
- Swift - 属性
- Swift - 方法
- Swift - 下标
- Swift - 继承
- Swift - 重写
- Swift - 初始化
- Swift - 析构
- Swift 高级
- Swift - ARC 概述
- Swift - 可选链
- Swift - 错误处理
- Swift - 并发
- Swift - 类型转换
- Swift - 嵌套类型
- Swift - 扩展
- Swift - 协议
- Swift - 泛型
- Swift - 访问控制
- Swift - 函数与方法
- Swift - SwiftyJSON
- Swift - 单例类
- Swift 随机数
- Swift 不透明类型和装箱类型
- Swift 有用资源
- Swift - 在线编译
- Swift 快速指南
- Swift - 有用资源
- Swift - 讨论
Swift 快速指南
Swift - 概述
Swift 4 是一种由 Apple Inc 开发的新编程语言,用于 iOS 和 OS X 开发。Swift 4 采用了 C 和 Objective-C 的优点,而没有 C 兼容性的限制。
Swift 4 利用安全的编程模式。
Swift 4 提供了现代的编程功能。
Swift 4 提供了类似 Objective-C 的语法。
Swift 4 是一种编写 iOS 和 OS X 应用程序的绝佳方式。
Swift 4 提供了对现有 Cocoa 框架的无缝访问。
Swift 4 将语言的过程部分和面向对象部分统一起来。
Swift 4 不需要单独的库导入来支持诸如输入/输出或字符串处理之类功能。
Swift 4 使用与 Mac OS 和 iOS 上现有的 Obj-C 系统相同的运行时,这使得 Swift 4 程序能够在许多现有的 iOS 6 和 OS X 10.8 平台上运行。
Swift 4 带有游乐场功能,Swift 4 程序员可以在其中编写代码并立即执行它以查看结果。
Swift 的第一个公开版本于 2010 年发布。Chris Lattner 花了近 14 年时间才开发出第一个正式版本,后来它得到了许多其他贡献者的支持。Swift 4 已包含在 Xcode 6 测试版中。
Swift 设计师从各种其他流行语言中汲取灵感,例如 Objective-C、Rust、Haskell、Ruby、Python、C# 和 CLU。
Swift - 环境
本地环境设置
Swift 4 提供了一个游乐场平台用于学习目的,我们将设置相同的平台。您需要 xCode 软件才能在游乐场中开始 Swift 4 编码。一旦您熟悉了 Swift 4 的概念,就可以使用 xCode IDE 进行 iOS/OS x 应用程序开发。
首先,我们假设您已经在 Apple Developer 网站上拥有一个帐户。登录后,访问以下链接:Apple 开发者下载
这将列出许多可用的软件,如下所示:
现在选择 xCode 并通过单击磁盘映像旁边的链接下载它。下载 dmg 文件后,只需双击它并按照给定的说明进行安装即可。最后,按照给定的说明将 xCode 图标拖放到应用程序文件夹中。
现在您已在您的机器上安装了 xCode。接下来,从应用程序文件夹中打开 Xcode,并在接受条款和条件后继续。如果一切正常,您将看到以下屏幕:
选择“使用游乐场开始”选项,并为游乐场输入一个名称,然后选择 iOS 作为平台。最后,您将获得以下游乐场窗口:
以下是从默认的 Swift 4 游乐场窗口获取的代码。
import UIKit var str = "Hello, playground"
如果您为 OS X 程序创建相同的程序,则它将包含 import Cocoa,程序将如下所示:
import Cocoa var str = "Hello, playground"
当上述程序加载时,它应该在游乐场结果区域(右侧)显示以下结果。
Hello, playground
恭喜,您已准备好 Swift 4 编程环境,您可以继续使用您的学习工具“教程点”。
Swift - 基本语法
在设置环境时,我们已经看到了 Swift 4 程序的一部分。让我们再次从以下为 OS X 游乐场创建的“Hello, World!”程序开始,其中包含import Cocoa,如下所示:
/* My first program in Swift 4 */ var myString = "Hello, World!" print(myString)
如果您为 iOS 游乐场创建相同的程序,则它将包含import UIKit,程序将如下所示:
import UIKit var myString = "Hello, World!" print(myString)
当我们使用合适的游乐场运行上述程序时,我们将得到以下结果:
Hello, World!
现在让我们看看 Swift 4 程序的基本结构,这样您就可以轻松理解 Swift 4 编程语言的基本构建块。
Swift 4 中的导入
您可以使用import语句将任何 Objective-C 框架(或 C 库)直接导入到您的 Swift 4 程序中。例如,上面的import cocoa语句使构成所有 OS X 开发层的 Cocoa 库、API 和运行时在 Swift 4 中可用。
Cocoa 是用 Objective-C 实现的,Objective-C 是 C 的超集,因此可以轻松地将 C 甚至 C++ 混合到您的 Swift 4 应用程序中。
Swift 4 中的标记
Swift 4 程序由各种标记组成,标记可以是关键字、标识符、常量、字符串文字或符号。例如,以下 Swift 4 语句由三个标记组成:
print("test!") The individual tokens are: print("test!")
注释
注释就像 Swift 4 程序中的帮助文本。编译器会忽略它们。多行注释以/*开头,以字符*/结尾,如下所示:
/* My first program in Swift 4 */
多行注释可以在 Swift 4 中嵌套。以下是 Swift 4 中的有效注释:
/* My first program in Swift 4 is Hello, World! /* Where as second program is Hello, Swift 4! */ */
单行注释以//开头。
// My first program in Swift 4
分号
Swift 4 不要求您在代码中每个语句后都输入分号(;),尽管它是可选的;如果您使用分号,则编译器不会报错。
但是,如果您在同一行中使用多个语句,则需要使用分号作为分隔符,否则编译器将引发语法错误。您可以将上述 Hello, World! 程序编写如下:
/* My first program in Swift 4 */ var myString = "Hello, World!"; print(myString)
标识符
Swift 4 标识符是用于识别变量、函数或任何其他用户定义项的名称。标识符以字母 A 到 Z 或 a 到 z 或下划线 _ 开头,后跟零个或多个字母、下划线和数字(0 到 9)。
Swift 4 不允许在标识符中使用特殊字符,例如 @、$ 和 %。Swift 4 是一种区分大小写的编程语言。因此,Manpower 和 manpower 在 Swift 4 中是两个不同的标识符。以下是一些可接受的标识符示例:
Azad zara abc move_name a_123 myname50 _temp j a23b9 retVal
要使用保留字作为标识符,您需要在它前后加上反引号(`)。例如,class不是有效的标识符,但`class`是有效的。
关键字
以下关键字在 Swift 4 中是保留的。这些保留字不能用作常量或变量或任何其他标识符名称,除非它们用反引号转义:
用于声明的关键字
类 | deinit | 枚举 | 扩展 |
Func | 导入 | 初始化 | 内部 |
Let | 运算符 | 私有 | 协议 |
公共 | 静态 | 结构体 | 下标 |
类型别名 | var |
用于语句的关键字
中断 | 案例 | 继续 | 默认 |
做 | 其他 | 贯穿 | 为了 |
如果 | 在 | 返回 | 开关 |
哪里 | 当 |
用于表达式和类型的关键字
作为 | dynamicType | 错误的 | 是 |
无效 | 自己 | 自我 | 超级 |
真的 | 列名 | 文件 | 函数 |
行号 |
特定上下文中使用的关键词
结合性 | 便利性 | 动态 | didSet |
最终 | 获取 | 中缀 | inout |
延迟 | 左 | 可变 | 无 |
不可变 | 可选 | 重写 | 后缀 |
优先级 | 前缀 | 协议 | 必需 |
右 | 设置 | 类型 | 非拥有 |
弱引用 | willSet |
空白符
仅包含空白符(可能还有注释)的行称为空行,Swift 4 编译器会完全忽略它。
在 Swift 4 中,空白符指的是空格、制表符、换行符和注释。空白符将语句的不同部分分隔开来,使编译器能够识别语句中一个元素(例如 int)的结束位置和下一个元素的开始位置。因此,在以下语句中:
var age
必须在var和age之间至少有一个空白字符(通常是空格),才能使编译器能够区分它们。另一方面,在以下语句中:
int fruit = apples + oranges //get the total fruits
在 fruit 和 = 之间,或者在 = 和 apples 之间,不需要空白字符,尽管您可以为了更好的可读性而添加一些空格。
运算符两侧的空格应相等,例如:
int fruit = apples +oranges //is a wrong statement int fruit = apples + oranges //is a Correct statement
字面量
字面量是整数、浮点数或字符串类型值的源代码表示形式。以下是字面量的示例:
92 // Integer literal 4.24159 // Floating-point literal "Hello, World!" // String literal
Swift 中的打印
要在 Swift 中打印任何内容,我们使用“print”关键字。
Print 有三个不同的属性。
项目 – 要打印的项目
分隔符 – 项目之间的分隔符
终止符 – 行应以哪个值结尾,让我们看一个示例和语法。
print("Items to print", separator: "Value " , terminator: "Value") // E.g. of print statement. print("Value one") // prints "Value one \n" Adds, \n as terminator and " " as separator by default. print("Value one","Value two", separator: " Next Value" , terminator: " End") //prints "Value one Next Value Value two End"
在上面的代码中,第一个 print 语句默认添加 \n(换行符)作为终止符,而在第二个 print 语句中,我们使用了“End”作为终止符,因此它将打印“End”而不是 \n。
我们可以根据需要提供自定义的分隔符和终止符。
Swift - 数据类型
在任何编程语言中进行编程时,都需要使用不同类型的变量来存储信息。变量只不过是保留的内存位置,用于存储值。这意味着当您创建变量时,会在内存中保留一些空间。
您可能希望存储各种数据类型的信息,例如字符串、字符、宽字符、整数、浮点数、布尔值等。根据变量的数据类型,操作系统会分配内存并确定可以在保留的内存中存储什么。
内置数据类型
Swift 4 为程序员提供了丰富的内置数据类型和用户自定义数据类型。在声明变量时,以下基本数据类型最常用:
Int 或 UInt – 用于表示整数。更具体地说,您可以使用 Int32、Int64 定义 32 位或 64 位有符号整数,而使用 UInt32 或 UInt64 定义 32 位或 64 位无符号整数变量。例如,42 和 -23。
Float – 用于表示 32 位浮点数和小数点较小的数字。例如,3.14159、0.1 和 -273.158。
Double – 用于表示 64 位浮点数,并在浮点值必须非常大的情况下使用。例如,3.14159、0.1 和 -273.158。
Bool – 表示布尔值,其值为真或假。
String – 字符的有序集合。例如,“Hello, World!”
Character – 单字符字符串字面量。例如,“C”
Optional – 表示可以保存值或不保存值的变量。
元组 – 用于将多个值组合到单个复合值中。
这里列出了与整数类型相关的一些重要要点:
在 32 位平台上,Int 与 Int32 大小相同。
在 64 位平台上,Int 与 Int64 大小相同。
在 32 位平台上,UInt 与 UInt32 大小相同。
在 64 位平台上,UInt 与 UInt64 大小相同。
Int8、Int16、Int32、Int64 可用于表示 8 位、16 位、32 位和 64 位的有符号整数。
UInt8、UInt16、UInt32 和 UInt64 可用于表示 8 位、16 位、32 位和 64 位的无符号整数。
边界值
下表显示了变量类型、存储值所需的内存大小以及可以在此类变量中存储的最大值和最小值。
类型 | 典型位宽 | 典型范围 |
---|---|---|
Int8 | 1 字节 | -127 到 127 |
UInt8 | 1 字节 | 0 到 255 |
Int32 | 4 字节 | -2147483648 到 2147483647 |
UInt32 | 4 字节 | 0 到 4294967295 |
Int64 | 8 字节 | -9223372036854775808 到 9223372036854775807 |
UInt64 | 8 字节 | 0 到 18446744073709551615 |
Float | 4 字节 | 1.2E-38 到 3.4E+38(约 6 位数字) |
Double | 8 字节 | 2.3E-308 到 1.7E+308(约 15 位数字) |
类型别名
您可以使用typealias为现有类型创建新名称。以下是使用 typealias 定义新类型的简单语法:
typealias newname = type
例如,以下行指示编译器Feet是Int的另一个名称:
typealias Feet = Int
现在,以下声明是完全合法的,并且创建了一个名为 distance 的整数变量:
typealias Feet = Int var distance: Feet = 100 print(distance)
当我们使用游乐场运行上述程序时,会得到以下结果。
100
类型安全
Swift 4 是一种类型安全的语言,这意味着如果代码的一部分期望一个字符串,则您不能错误地传递一个整数。
由于 Swift 4 是类型安全的,因此它在编译代码时会执行类型检查,并将任何不匹配的类型标记为错误。
var varA = 42 varA = "This is hello" print(varA)
当我们编译上述程序时,会产生以下编译时错误。
main.swift:2:8: error: cannot assign value of type 'String' to type 'Int' varA = "This is hello"
类型推断
类型推断使编译器能够在编译代码时自动推断特定表达式的类型,只需检查您提供的值即可。Swift 4 使用类型推断来确定适当的类型,如下所示。
// varA is inferred to be of type Int var varA = 42 print(varA) // varB is inferred to be of type Double var varB = 3.14159 print(varB) // varC is also inferred to be of type Double var varC = 3 + 0.14159 print(varC)
当我们使用游乐场运行上述程序时,会得到以下结果:
42 3.14159 3.14159
Swift - 变量
变量为我们提供了程序可以操作的命名存储。Swift 4 中的每个变量都具有特定的类型,该类型决定了变量内存的大小和布局;可以在该内存中存储的值范围;以及可以应用于变量的操作集。
Swift 4 支持以下基本类型的变量:
Int 或 UInt – 用于表示整数。更具体地说,您可以使用 Int32、Int64 定义 32 位或 64 位有符号整数,而使用 UInt32 或 UInt64 定义 32 位或 64 位无符号整数变量。例如,42 和 -23。
Float – 用于表示 32 位浮点数。它用于保存小数点较小的数字。例如,3.14159、0.1 和 -273.158。
Double – 用于表示 64 位浮点数,并在浮点值必须非常大的情况下使用。例如 3.14159、0.1 和 -273.158。
Bool – 表示布尔值,其值为真或假。
String – 字符的有序集合。例如,“Hello, World!”
Character – 单字符字符串字面量。例如,“C”
Swift 4 还允许定义各种其他类型的变量,我们将在后续章节中介绍,例如Optional、Array、Dictionaries、Structures和Classes。
下一节将介绍如何在 Swift 4 编程中声明和使用各种类型的变量。
变量声明
变量声明告诉编译器在哪里以及如何创建变量的存储空间。在使用变量之前,必须使用var关键字声明它们,如下所示:
var variableName = <initial value>
以下示例显示了如何在 Swift 4 中声明变量:
var varA = 42 print(varA)
当我们使用游乐场运行上述程序时,会得到以下结果:
42
类型注释
在声明变量时,您可以提供类型注释,以明确变量可以存储的值的类型。以下是语法:
var variableName:<data type> = <optional initial value>
以下示例显示了如何在 Swift 4 中使用注释声明变量。这里需要注意的是,如果我们不使用类型注释,那么必须为变量提供初始值,否则我们只需使用类型注释声明变量即可。
var varA = 42 print(varA) var varB:Float varB = 3.14159 print(varB)
当我们使用游乐场运行上述程序时,会得到以下结果:
42 3.1415901184082
变量命名
变量名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大小写字母是不同的,因为 Swift 4 是一种区分大小写的编程语言。
您可以使用简单字符或 Unicode 字符为变量命名。以下示例显示了如何命名变量:
var _var = "Hello, Swift 4!" print(_var) var 你好 = "你好世界" print(你好)
当我们使用游乐场运行上述程序时,会得到以下结果。
Hello, Swift 4! 你好世界
打印变量
您可以使用 print 函数打印常量或变量的当前值。您可以通过将名称括在括号中并在开头加上反斜杠来内插变量值:以下是有效的示例:
var varA = "Godzilla" var varB = 1000.00 print("Value of \(varA) is more than \(varB) millions")
当我们使用游乐场运行上述程序时,会得到以下结果。
Value of Godzilla is more than 1000.0 millions
Swift - 可选类型
Swift 4 还引入了可选类型,它处理值的缺失。可选类型表示“存在一个值,并且它等于 x”或“根本不存在值”。
可选类型本身就是一种类型,实际上是 Swift 4 的新的超级枚举之一。它有两个可能的值,None和Some(T),其中T是在 Swift 4 中可用的正确数据类型的关联值。
这是一个可选整数声明:
var perhapsInt: Int?
这是一个可选字符串声明:
var perhapsStr: String?
上述声明等同于显式地将其初始化为nil,这意味着没有值:
var perhapsStr: String? = nil
让我们以以下示例来了解可选类型如何在 Swift 4 中工作:
var myString:String? = nil if myString != nil { print(myString) } else { print("myString has nil value") }
当我们使用游乐场运行上述程序时,会得到以下结果:
myString has nil value
可选类型类似于在 Objective-C 中使用指针的nil,但它们适用于任何类型,而不仅仅是类。
强制解包
如果您将变量定义为可选类型,则要获取该变量的值,您必须对其进行解包。这仅仅意味着在变量的末尾加上感叹号。
让我们来看一个简单的例子:
var myString:String? myString = "Hello, Swift 4!" if myString != nil { print(myString) } else { print("myString has nil value") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Optional("Hello, Swift 4!")
现在让我们应用解包来获取变量的正确值:
var myString:String? myString = "Hello, Swift 4!" if myString != nil { print( myString! ) } else { print("myString has nil value") }
当我们使用游乐场运行上述程序时,会得到以下结果。
Hello, Swift 4!
自动解包
您可以使用感叹号而不是问号来声明可选变量。此类可选变量将自动解包,您无需在变量末尾再使用任何感叹号即可获取分配的值。让我们来看一个简单的例子:
var myString:String! myString = "Hello, Swift 4!" if myString != nil { print(myString) } else { print("myString has nil value") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Hello, Swift 4!
可选绑定
使用可选绑定来确定可选类型是否包含值,如果包含,则将其值作为临时常量或变量提供。
if 语句的一个可选绑定如下所示:
if let constantName = someOptional { statements }
让我们来看一个简单的例子来理解可选绑定的用法:
var myString:String? myString = "Hello, Swift 4!" if let yourString = myString { print("Your string has - \(yourString)") } else { print("Your string does not have a value") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Your string has - Hello, Swift 4!
Swift - 元组
Swift 4 还引入了元组类型,用于将多个值组合成一个复合值。
元组中的值可以是任何类型,并且不需要是相同的类型。
例如,("Tutorials Point", 123) 是一个包含两个值的元组,一个为字符串类型,另一个为整数类型。这是一个合法的命令。
let ImplementationError = (501, "Not implemented") 是服务器上某些内容未实现时的错误,它返回两个值:错误代码和描述。
您可以根据需要从任意数量的值和任意数量的不同数据类型创建元组。
以下是元组声明的语法:
var TupleName = (Value1, value2,… any number of values)
这是一个元组声明:
var error501 = (501, “Not implemented”)
您可以使用从 0 开始的索引号访问元组的值。
以下是如何访问元组值的示例:
print(“The code is\(error501.0)”) print(“The definition of error is\(error501.1)”)
您可以在声明时命名元组的变量,并且可以使用其名称来调用它们。
var error501 = (errorCode: 501, description: “Not Implemented”) print(error501.errorCode) // prints 501.
元组有助于从函数中返回多个值。例如,一个 Web 应用程序可能会返回类型为 ("String", Int) 的元组,以显示加载是否成功。
通过在元组中返回不同的值,我们可以根据不同的元组类型做出决策。
注意 - 元组适用于临时值,不适合复杂数据。
Swift - 常量
常量是指程序在其执行过程中可能不会更改的固定值。常量可以是任何基本数据类型,例如整数常量、浮点常量、字符常量或字符串字面量。还有枚举常量。
常量与普通变量一样,只是在定义后其值不能被修改。
常量声明
在使用常量之前,必须使用let关键字声明它们,如下所示:
let constantName = <initial value>
以下是一个简单的示例,演示如何在 Swift 4 中声明常量:
let constA = 42 print(constA)
当我们使用游乐场运行上述程序时,会得到以下结果:
42
类型注释
您可以在声明常量时提供类型注解,以明确常量可以存储的值的类型。以下是语法:
var constantName:<data type> = <optional initial value>
以下示例演示了如何在 Swift 4 中使用注解声明常量。这里需要注意的是,在创建常量时必须提供初始值:
let constA = 42 print(constA) let constB:Float = 3.14159 print(constB)
当我们使用游乐场运行上述程序时,会得到以下结果。
42 3.1415901184082
命名常量
常量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大小写字母是不同的,因为 Swift 4 是一种区分大小写的编程语言。
您可以使用简单字符或 Unicode 字符来命名变量。以下是有效的示例:
let _const = "Hello, Swift 4!" print(_const) let 你好 = "你好世界" print(你好)
当我们使用游乐场运行上述程序时,会得到以下结果:
Hello, Swift 4! 你好世界
打印常量
您可以使用print函数打印常量或变量的当前值。您可以通过将名称括在括号中并使用反斜杠转义开头括号来内插变量值:以下是有效的示例:
let constA = "Godzilla" let constB = 1000.00 print("Value of \(constA) is more than \(constB) millions")
当我们使用游乐场运行上述程序时,会得到以下结果:
Value of Godzilla is more than 1000.0 millions
Swift - 字面量
字面量是整数、浮点数或字符串类型值的源代码表示形式。以下是字面量的示例:
42 // Integer literal 3.14159 // Floating-point literal "Hello, world!" // String literal
整数字面量
整数字面量可以是十进制、二进制、八进制或十六进制常量。二进制字面量以 0b 开头,八进制字面量以 0o 开头,十六进制字面量以 0x 开头,十进制则没有前缀。
以下是一些整数字面量的示例:
let decimalInteger = 17 // 17 in decimal notation let binaryInteger = 0b10001 // 17 in binary notation let octalInteger = 0o21 // 17 in octal notation let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
浮点数字面量
浮点数字面量包含整数部分、小数点、小数部分和指数部分。您可以以十进制形式或十六进制形式表示浮点数字面量。
十进制浮点数字面量由一系列十进制数字组成,后跟小数部分、十进制指数或两者兼而有之。
十六进制浮点数字面量由 0x 前缀、可选的十六进制小数部分和十六进制指数组成。
以下是一些浮点数字面量的示例:
let decimalDouble = 12.1875 let exponentDouble = 1.21875e1 let hexadecimalDouble = 0xC.3p0
字符串字面量
字符串字面量是由双引号括起来的一系列字符,格式如下:
"characters"
字符串字面量不能包含未转义的双引号 (")、未转义的反斜杠 (\)、回车符或换行符。可以使用以下转义序列在字符串字面量中包含特殊字符:
转义序列 | 含义 |
---|---|
\0 | 空字符 |
\\ | \character |
\b | 退格 |
\f | 换页 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\' | 单引号 |
\" | 双引号 |
\000 | 1 到 3 位的八进制数 |
\xhh... | 一个或多个数字的十六进制数 |
以下示例演示了如何使用一些字符串字面量:
let stringL = "Hello\tWorld\n\nHello\'Swift 4\'" print(stringL)
当我们使用游乐场运行上述程序时,会得到以下结果:
Hello World Hello'Swift 4'
布尔字面量
有三个布尔字面量,它们是标准 Swift 4 关键字的一部分:
true 值表示真。
false 值表示假。
nil 值表示没有值。
Swift - 运算符
运算符是告诉编译器执行特定数学或逻辑操作的符号。Objective-C 拥有丰富的内置运算符,并提供以下类型的运算符:
- 算术运算符
- 比较运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 范围运算符
- 其他运算符
本教程将逐一解释算术、关系、逻辑、位、赋值和其他运算符。
算术运算符
下表显示了 Swift 4 语言支持的所有算术运算符。假设变量A为 10,变量B为 20,则:
运算符 | 描述 | 示例 |
---|---|---|
+ | 将两个操作数相加 | A + B 将得到 30 |
− | 从第一个操作数中减去第二个操作数 | A − B 将得到 -10 |
* | 将两个操作数相乘 | A * B 将得到 200 |
/ | 将分子除以分母 | B / A 将得到 2 |
% | 模运算符和整数/浮点数除法后的余数 | B % A 将得到 0 |
比较运算符
下表显示了 Swift 4 语言支持的所有关系运算符。假设变量A为 10,变量B为 20,则:
运算符 | 描述 | 示例 |
---|---|---|
== | 检查两个操作数的值是否相等;如果相等,则条件为真。 | (A == B) 为假。 |
!= | 检查两个操作数的值是否不相等;如果不相等,则条件为真。 | (A != B) 为真。 |
> | 检查左操作数的值是否大于右操作数的值;如果大于,则条件为真。 | (A > B) 为假。 |
< | 检查左操作数的值是否小于右操作数的值;如果小于,则条件为真。 | (A < B) 为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值;如果大于或等于,则条件为真。 | (A >= B) 为假。 |
<= | 检查左操作数的值是否小于或等于右操作数的值;如果小于或等于,则条件为真。 | (A <= B) 为真。 |
逻辑运算符
下表显示了 Swift 4 语言支持的所有逻辑运算符。假设变量A为 1,变量B为 0,则:
运算符 | 描述 | 示例 |
---|---|---|
&& | 称为逻辑与运算符。如果两个操作数均非零,则条件为真。 | (A && B) 为假。 |
|| | 称为逻辑或运算符。如果两个操作数中的任何一个非零,则条件为真。 | (A || B) 为真。 |
! | 称为逻辑非运算符。用于反转其操作数的逻辑状态。如果条件为真,则逻辑非运算符将使其为假。 | !(A && B) 为真。 |
位运算符
位运算符作用于位并执行逐位操作。&、| 和 ^ 的真值表如下:
p | q | p&q | p|q | p^q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
Assume A = 60; and B = 13; In binary format, they will be as follows: A = 0011 1100 B = 0000 1101 ----------------- A & B = 0000 1100 A|B = 0011 1101 A^B = 0011 0001 ~A = 1100 0011
Swift 4 语言支持的位运算符列在下表中。假设变量A为 60,变量B为 13,则 7−
运算符 | 描述 | 示例 |
---|---|---|
& | 二进制与运算符将位复制到结果中,如果它存在于两个操作数中。 | (A & B) 将得到 12,即 0000 1100 |
| | 二进制或运算符将位复制,如果它存在于任何一个操作数中。 | (A | B) 将得到 61,即 0011 1101 |
^ | 二进制异或运算符将位复制,如果它在一个操作数中设置,但在两个操作数中都不设置。 | (A ^ B) 将得到 49,即 0011 0001 |
~ | 二进制一补码运算符是一元运算符,其作用是“翻转”位。 | (~A ) 将得到 -61,在 2 的补码形式中为 1100 0011。 |
<< | 二进制左移运算符。左操作数的值向左移动由右操作数指定的位数。 | (A << 2 将得到 240,即 1111 0000 |
>> | 二进制右移运算符。左操作数的值向右移动由右操作数指定的位数。 | A >> 2 将得到 15,即 0000 1111 |
赋值运算符
Swift 4 支持以下赋值运算符:
运算符 | 描述 | 示例 |
---|---|---|
= | 简单赋值运算符,将右侧操作数的值赋给左侧操作数 | C = A + B 将 A + B 的值赋给 C |
+= | 加并赋值运算符,它将右侧操作数加到左侧操作数上并将结果赋给左侧操作数 | C += A 等价于 C = C + A |
-= | 减并赋值运算符,它从左侧操作数中减去右侧操作数并将结果赋给左侧操作数 | C -= A 等价于 C = C - A |
*= | 乘并赋值运算符,它将右侧操作数乘以左侧操作数并将结果赋给左侧操作数 | C *= A 等价于 C = C * A |
/= | 除并赋值运算符,它将左侧操作数除以右侧操作数并将结果赋给左侧操作数 | C /= A 等价于 C = C / A |
%= | 模并赋值运算符,它使用两个操作数取模并将结果赋给左侧操作数 | C %= A 等价于 C = C % A |
<<= | 左移并赋值运算符 | C <<= 2 与 C = C << 2 相同 |
>>= | 右移并赋值运算符 | C >>= 2 与 C = C >> 2 相同 |
&= | 按位与并赋值运算符 | C &= 2 与 C = C & 2 相同 |
^= | 按位异或并赋值运算符 | C ^= 2 与 C = C ^ 2 相同 |
|= | 按位或并赋值运算符 | C |= 2 与 C = C | 2 相同 |
范围运算符
Swift 4 包含两个范围运算符,它们是表示值范围的快捷方式。下表解释了这两个运算符。
运算符 | 描述 | 示例 |
---|---|---|
闭合范围 | (a...b) 定义一个从 a 到 b 的范围,包括值 a 和 b。 | 1...5 给出 1、2、3、4 和 5 |
半开范围 | (a..< b) 定义一个从 a 到 b 的范围,但不包括 b。 | 1..< 5 给出 1、2、3 和 4 |
单侧范围 |
a… ,定义一个从 a 到元素结尾的范围 …a ,定义一个从开始到 a 的范围 |
1… 给出 1、2、3… 元素的结尾 …2 给 1,2 的开头… |
其他运算符
Swift 4 支持其他一些重要的运算符,包括范围和 ? :,这些运算符将在下表中解释。
运算符 | 描述 | 示例 |
---|---|---|
一元减号 | 可以使用前缀 - 切换数值符号。 | -3 或 -4 |
一元加号 | 返回其操作的值,没有任何更改。 | +6 给出 6 |
三元条件运算符 | Condition ? X : Y | 如果 Condition 为真 ? 则值为 X : 否则值为 Y |
运算符优先级
运算符优先级决定表达式中项的组合方式。这会影响表达式的计算方式。某些运算符比其他运算符具有更高的优先级;例如,乘法运算符的优先级高于加法运算符。
例如,x = 7 + 3 * 2;在这里,x 被赋值为 13,而不是 20,因为运算符 * 的优先级高于 +,所以它首先与 3*2 相乘,然后加到 7 中。
这里,优先级最高的运算符出现在表格的顶部,优先级最低的出现在底部。在表达式中,优先级较高的运算符将首先被计算。
运算符 | 描述 | 示例 |
---|---|---|
主表达式运算符 | () [] . expr++ expr-- | 从左到右 |
一元运算符 |
* & + - ! ~ ++expr --expr * / % + - >> << < > <= >= == != |
从右到左 |
二元运算符 |
& ^ | && || |
从左到右 |
三元运算符 | ?: | 从右到左 |
赋值运算符 | = += -= *= /= %= >>= <<= &=^= |= | 从右到左 |
逗号 | , | 从左到右 |
Swift - 决策控制
决策结构要求程序员指定一个或多个条件供程序评估或测试,以及如果条件确定为true则要执行的语句,以及可选地,如果条件确定为false则要执行的其他语句。
以下是大多数编程语言中典型的决策结构的一般形式:
Swift 4 提供以下类型的决策语句。点击以下链接查看其详细信息。
序号 | 语句 & 描述 |
---|---|
1 | if 语句
if 语句由一个布尔表达式后跟一个或多个语句组成。 |
2 | if...else 语句
if 语句后面可以跟一个可选的 else 语句,当布尔表达式为假时执行。 |
3 | if...else if...else 语句
if 语句后面可以跟一个可选的 else if...else 语句,这对于使用单个 if...else if 语句测试各种条件非常有用。 |
4 | 嵌套 if 语句
可以在另一个 if 或 else if 语句中使用一个 if 或 else if 语句。 |
5 | switch 语句
switch 语句允许测试变量是否与值列表相等。 |
?:运算符
我们在上一章中介绍了条件运算符 ? :,它可以用来替换if...else语句。它具有以下一般形式:
Exp1 ? Exp2 : Exp3;
其中 Exp1、Exp2 和 Exp3 是表达式。注意冒号的使用和放置。
?表达式的值是这样确定的:计算 Exp1。如果为真,则计算 Exp2 并将其成为整个?表达式的值。如果 Exp1 为假,则计算 Exp3 并将其值成为表达式的值。
Swift - 循环
可能存在需要多次执行代码块的情况。通常,语句按顺序执行:函数中的第一个语句首先执行,然后是第二个语句,依此类推。
编程语言提供各种控制结构,允许更复杂的执行路径。
循环语句允许我们多次执行语句或语句组。以下是大多数编程语言中循环语句的一般形式:
Swift 4 编程语言提供以下几种循环来处理循环需求。点击以下链接查看其详细信息。
序号 | 循环类型 & 描述 |
---|---|
1 | for-in
此循环对范围、序列、集合或级数中的每个项目执行一组语句。 |
2 | while 循环
在给定条件为真时重复执行语句或语句组。它在执行循环体之前测试条件。 |
3 | repeat...while 循环
类似于 while 语句,只是它在循环体结束时测试条件。 |
循环控制语句
循环控制语句更改其正常顺序的执行。当执行离开作用域时,在该作用域中创建的所有自动对象都会被销毁。
Swift 4 支持以下控制语句。点击以下链接查看其详细信息。
序号 | 控制语句 & 描述 |
---|---|
1 | continue 语句
此语句告诉循环停止其正在执行的操作,并从循环的下一次迭代的开头重新开始。 |
2 | break 语句
终止循环语句并将执行转移到循环后紧跟的语句。 |
3 | fallthrough 语句
fallthrough 语句模拟 Swift 4 switch 对 C 样式 switch 的行为。 |
Swift - 字符串
Swift 4 中的字符串是有序字符集合,例如“Hello, World!”,它们由 Swift 4 数据类型String表示,而String又表示Character类型值的集合。
创建字符串
您可以使用字符串文字或创建 String 类的实例来创建字符串,如下所示:
// String creation using String literal var stringA = "Hello, Swift 4!" print( stringA ) // String creation using String instance var stringB = String("Hello, Swift 4!") print( stringB ) //Multiple line string let stringC = """ Hey this is a example of multiple Line string by tutorialsPoint """ print(stringC)
当上述代码编译并执行时,会产生以下结果
Hello, Swift 4! Hello, Swift 4! Hey this is a example of multiple Line string by tutorialsPoint
空字符串
您可以使用空字符串文字或创建 String 类实例来创建空字符串,如下所示。您还可以使用布尔属性isEmpty检查字符串是否为空。
// Empty string creation using String literal var stringA = "" if stringA.isEmpty { print( "stringA is empty" ) } else { print( "stringA is not empty" ) } // Empty string creation using String instance let stringB = String() if stringB.isEmpty { print( "stringB is empty" ) } else { print( "stringB is not empty" ) }
当上述代码编译并执行时,会产生以下结果:
stringA is empty stringB is empty
字符串常量
您可以通过将其分配给变量来指定您的字符串是否可以修改(或变异),或者通过使用let关键字将其分配给常量来使其成为常量,如下所示:
// stringA can be modified var stringA = "Hello, Swift 4!" stringA + = "--Readers--" print( stringA ) // stringB can not be modified let stringB = String("Hello, Swift 4!") stringB + = "--Readers--" print( stringB )
当上述代码编译并执行时,会产生以下结果:
Playground execution failed: error: <EXPR>:10:1: error: 'String' is not convertible to '@lvalue UInt8' stringB + = "--Readers--"
字符串插值
字符串插值是一种通过在字符串文字中包含其值来从常量、变量、文字和表达式的混合构建新的 String 值的方法。
您插入字符串文字中的每个项目(变量或常量)都用括号括起来,前面加上反斜杠。这是一个简单的例子:
var varA = 20 let constA = 100 var varC:Float = 20.0 var stringA = "\(varA) times \(constA) is equal to \(varC * 100)" print( stringA )
当上述代码编译并执行时,会产生以下结果:
20 times 100 is equal to 2000.0
字符串连接
您可以使用 + 运算符连接两个字符串或一个字符串和一个字符,或两个字符。这是一个简单的例子:
let constA = "Hello," let constB = "World!" var stringA = constA + constB print( stringA )
当上述代码编译并执行时,会产生以下结果:
Hello,World!
字符串长度
Swift 4 字符串没有length属性,但您可以使用全局 count() 函数计算字符串中的字符数。这是一个简单的例子:
var varA = "Hello, Swift 4!" print( "\(varA), length is \((varA.count))" )
当上述代码编译并执行时,会产生以下结果:
Hello, Swift 4!, length is 15
字符串比较
您可以使用 == 运算符比较两个字符串变量或常量。这是一个简单的例子:
var varA = "Hello, Swift 4!" var varB = "Hello, World!" if varA == varB { print( "\(varA) and \(varB) are equal" ) } else { print( "\(varA) and \(varB) are not equal" ) }
当上述代码编译并执行时,会产生以下结果:
Hello, Swift 4! and Hello, World! are not equal
字符串迭代
字符串在 swift 4 中再次是值的集合,因此我们可以使用循环遍历字符串。
for chars in "ThisString" { print(chars, terminator: " ") }
当上述代码编译并执行时,会产生以下结果:
T h i s S t r i n g
Unicode 字符串
您可以通过遍历其 utf8 和 utf16 属性来访问字符串的 UTF-8 和 UTF-16 表示形式,如下例所示:
var unicodeString = "Dog???" print("UTF-8 Codes: ") for code in unicodeString.utf8 { print("\(code) ") } print("\n") print("UTF-16 Codes: ") for code in unicodeString.utf16 { print("\(code) ") }
当上述代码编译并执行时,会产生以下结果:
UTF-8 Codes: 68 111 103 63 63 63 UTF-16 Codes: 68 111 103 63 63 63
字符串函数 & 运算符
Swift 4 支持与字符串相关的各种方法和运算符:
序号 | 函数/运算符 & 目的 |
---|---|
1 | isEmpty 一个布尔值,用于确定字符串是否为空。 |
2 | hasPrefix(prefix: String) 函数用于检查给定参数字符串是否作为字符串的前缀存在。 |
3 | hasSuffix(suffix: String) 函数用于检查给定参数字符串是否作为字符串的后缀存在。 |
4 | toInt() 函数用于将数字字符串值转换为整数。 |
5 | count() 全局函数,用于计算字符串中的字符数。 |
6 | utf8 属性用于返回字符串的 UTF-8 表示形式。 |
7 | utf16 属性用于返回字符串的 UTF-16 表示形式。 |
8 | unicodeScalars 属性用于返回字符串的 Unicode 标量表示形式。 |
9 | + 运算符用于连接两个字符串,或一个字符串和一个字符,或两个字符。 |
10 | += 运算符用于将字符串或字符附加到现有字符串。 |
11 | == 运算符用于确定两个字符串是否相等。 |
12 | < 运算符用于执行词法比较以确定一个字符串是否小于另一个字符串。 |
13 | startIndex 获取字符串起始索引处的值。 |
14 | endIndex 获取字符串结束索引处的值。 |
15 | Indices 逐个访问索引。即字符串的所有字符。 |
16 | insert("Value", at: position) 在指定位置插入值。 |
17 |
remove(at: position) removeSubrange(range) 在指定位置删除值,或从字符串中删除一系列值。 |
18 | reversed() 返回字符串的反转。 |
Swift - 字符
Swift 中的字符是单个字符的字符串文字,由数据类型Character寻址。请查看以下示例。它使用了两个 Character 常量:
let char1: Character = "A" let char2: Character = "B" print("Value of char1 \(char1)") print("Value of char2 \(char2)")
当上述代码编译并执行时,会产生以下结果:
Value of char1 A Value of char2 B
如果您尝试在 Character 类型变量或常量中存储多个字符,则 Swift 4 将不允许这样做。尝试在 Swift 4 Playground 中键入以下示例,您甚至会在编译前收到错误。
// Following is wrong in Swift 4 let char: Character = "AB" print("Value of char \(char)")
空字符变量
无法创建具有空值的空字符变量或常量。以下语法是不可能的:
// Following is wrong in Swift 4 let char1: Character = "" var char2: Character = "" print("Value of char1 \(char1)") print("Value of char2 \(char2)")
从字符串中访问字符
如在讨论 Swift 4 的字符串时所述,String 以指定的顺序表示 Character 值的集合。因此,我们可以通过使用for-in循环迭代给定字符串来访问各个字符:
for ch in "Hello" { print(ch) }
当上述代码编译并执行时,会产生以下结果:
H e l l o
连接字符串和字符
以下示例演示了如何将 Swift 4 的 Character 与 Swift 4 的 String 连接起来。
var varA:String = "Hello " let varB:Character = "G" varA.append( varB ) print("Value of varC = \(varA)")
当上述代码编译并执行时,会产生以下结果:
Value of varC = Hello G
Swift - 数组
Swift 4 数组用于存储相同类型值的排序列表。Swift 4 进行严格的检查,不允许您即使错误地输入错误类型的数组。
如果您将创建的数组分配给变量,则它始终是可变的,这意味着您可以通过添加、删除或更改其项目来更改它;但是,如果您将数组分配给常量,则该数组是不可变的,其大小和内容无法更改。
创建数组
您可以使用以下初始化程序语法创建特定类型的空数组:
var someArray = [SomeType]()
以下是创建给定大小 a* 的数组并使用值对其进行初始化的语法:
var someArray = [SomeType](count: NumbeOfElements, repeatedValue: InitialValue)
您可以使用以下语句创建一个包含 3 个元素且初始值为零的空 **Int** 类型数组:
var someInts = [Int](count: 3, repeatedValue: 0)
以下是如何创建包含三个元素的数组并为该数组分配三个值的另一个示例:
var someInts:[Int] = [10, 20, 30]
访问数组
您可以使用 **下标** 语法从数组中检索值,在数组名称后立即使用方括号传递要检索的值的索引,如下所示:
var someVar = someArray[index]
这里,**索引** 从 0 开始,这意味着第一个元素可以使用索引 0 访问,第二个元素可以使用索引 1 访问,依此类推。以下示例演示如何创建、初始化和访问数组:
var someInts = [Int](count: 3, repeatedValue: 10) var someVar = someInts[0] print( "Value of first element is \(someVar)" ) print( "Value of second element is \(someInts[1])" ) print( "Value of third element is \(someInts[2])" )
当上述代码编译并执行时,会产生以下结果:
Value of first element is 10 Value of second element is 10 Value of third element is 10
修改数组
您可以使用 **append()** 方法或加法赋值运算符(+=)在数组末尾添加新项目。请查看以下示例。在这里,我们首先创建一个空数组,然后向同一个数组中添加新元素:
var someInts = [Int]() someInts.append(20) someInts.append(30) someInts += [40] var someVar = someInts[0] print( "Value of first element is \(someVar)" ) print( "Value of second element is \(someInts[1])" ) print( "Value of third element is \(someInts[2])" )
当上述代码编译并执行时,会产生以下结果:
Value of first element is 20 Value of second element is 30 Value of third element is 40
您可以通过在给定索引处分配新值来修改数组的现有元素,如以下示例所示:
var someInts = [Int]() someInts.append(20) someInts.append(30) someInts += [40] // Modify last element someInts[2] = 50 var someVar = someInts[0] print( "Value of first element is \(someVar)" ) print( "Value of second element is \(someInts[1])" ) print( "Value of third element is \(someInts[2])" )
当上述代码编译并执行时,会产生以下结果:
Value of first element is 20 Value of second element is 30 Value of third element is 50
遍历数组
您可以使用 **for-in** 循环遍历数组中的所有值,如以下示例所示:
var someStrs = [String]() someStrs.append("Apple") someStrs.append("Amazon") someStrs += ["Google"] for item in someStrs { print(item) }
当上述代码编译并执行时,会产生以下结果:
Apple Amazon Google
您可以使用 **enumerate()** 函数,该函数返回项目的索引及其值,如下面的示例所示:
var someStrs = [String]() someStrs.append("Apple") someStrs.append("Amazon") someStrs += ["Google"] for (index, item) in someStrs.enumerated() { print("Value at index = \(index) is \(item)") }
当上述代码编译并执行时,会产生以下结果:
Value at index = 0 is Apple Value at index = 1 is Amazon Value at index = 2 is Google
添加两个数组
您可以使用加法运算符(+)来添加两个相同类型的数组,这将生成一个新数组,其中包含来自这两个数组的值的组合,如下所示:
var intsA = [Int](count:2, repeatedValue: 2) var intsB = [Int](count:3, repeatedValue: 1) var intsC = intsA + intsB for item in intsC { print(item) }
当上述代码编译并执行时,会产生以下结果:
2 2 1 1 1
count 属性
您可以使用数组的只读 **count** 属性来查找数组中的项目数量,如下所示:
var intsA = [Int](count:2, repeatedValue: 2) var intsB = [Int](count:3, repeatedValue: 1) var intsC = intsA + intsB print("Total items in intsA = \(intsA.count)") print("Total items in intsB = \(intsB.count)") print("Total items in intsC = \(intsC.count)")
当上述代码编译并执行时,会产生以下结果:
Total items in intsA = 2 Total items in intsB = 3 Total items in intsC = 5
empty 属性
您可以使用数组的只读 **empty** 属性来确定数组是否为空,如下所示:
var intsA = [Int](count:2, repeatedValue: 2) var intsB = [Int](count:3, repeatedValue: 1) var intsC = [Int]() print("intsA.isEmpty = \(intsA.isEmpty)") print("intsB.isEmpty = \(intsB.isEmpty)") print("intsC.isEmpty = \(intsC.isEmpty)")
当上述代码编译并执行时,会产生以下结果:
intsA.isEmpty = false intsB.isEmpty = false intsC.isEmpty = true
Swift - 集合
Swift 4 中的 **集合** 用于存储相同类型但没有像数组那样具有确定顺序的唯一值。
如果元素的顺序不是问题,或者您想确保没有重复值,则可以使用集合而不是数组。(集合只允许唯一值。)
要存储在集合中,类型必须是可散列的。散列值是一个 Int 值,对于相等的 objects 来说是相等的。例如,如果 x == y,则 **x.hashvalue == y.hashvalue**。
默认情况下,所有基本的 Swift 值都是可散列类型,可以用作集合值。
创建集合
您可以使用以下初始化程序语法创建特定类型的空集合:
var someSet = Set<Character>() //Character can be replaced by data type of set.
访问和修改集合
您可以使用其方法和属性来访问或修改集合:
"count" 方法可用于显示集合中元素的数量。
someSet.count // prints the number of elements
"insert" 方法可用于在集合中插入值。
someSet.insert("c") // adds the element to Set.
类似地,isEmpty 可用于检查集合是否为空。
someSet.isEmpty // returns true or false depending on the set Elements.
"remove" 方法可用于删除集合中的值。
someSet.remove("c") // removes a element , removeAll() can be used to remove all elements
"contains" 方法可用于检查集合中是否存在值。
someSet.contains("c") // to check if set contains this value.
遍历集合
您可以使用 for-in 循环遍历集合:
for items in someSet { print(someSet) } //Swift sets are not in an ordered way, to iterate over a set in ordered way use for items in someSet.sorted() { print(someSet) }
执行集合操作
您可以在 Swift 集合上执行基本的集合操作。
以下是执行集合操作的方法:
- 交集
- 并集
- 减法
let evens: Set = [10,12,14,16,18] let odds: Set = [5,7,9,11,13] let primes = [2,3,5,7] odds.union(evens).sorted() // [5,7,9,10,11,12,13,14,16,18] odds.intersection(evens).sorted() //[] odds.subtracting(primes).sorted() //[9, 11, 13]
Swift - 字典
Swift 4 中的 **字典** 用于存储相同类型的值的无序列表。Swift 4 进行了严格的检查,即使不小心,也不会允许您在字典中输入错误的类型。
Swift 4 字典使用称为 **键** 的唯一标识符来存储值,稍后可以通过相同的键引用和查找该值。与数组中的项目不同,**字典** 中的项目没有指定的顺序。当您需要根据标识符查找值时,可以使用 **字典**。
字典键可以是整数或字符串,没有限制,但它在字典中必须是唯一的。
如果您将创建的字典分配给变量,则它始终是可变的,这意味着您可以通过添加、删除或更改其项目来更改它。但是,如果您将字典分配给常量,则该字典是不可变的,其大小和内容无法更改。
创建字典
您可以使用以下初始化程序语法创建特定类型的空字典:
var someDict = [KeyType: ValueType]()
您可以使用以下简单语法创建键为 Int 类型且关联值为字符串的空字典:
var someDict = [Int: String]()
这是一个根据给定值集创建字典的示例:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
基于序列的初始化
Swift 4 允许您从数组(键值对)创建字典。
var cities = [“Delhi”,”Bangalore”,”Hyderabad”]
您可以使用以下简单语法创建键为 Int 类型且关联值为字符串的空字典:
var Distance = [2000,10, 620]
这是一个根据给定值集创建字典的示例:
let cityDistanceDict = Dictionary(uniqueKeysWithValues: zip(cities, Distance))
以上代码行将创建一个字典,其中 Cities 为键,Distance 为值:
过滤
Swift 4 允许您从字典中过滤值。
var closeCities = cityDistanceDict.filter { $0.value < 1000 }
如果我们运行以上代码,我们的 closeCities 字典将是。
["Bangalore" : 10 , "Hyderabad" : 620]
字典分组
Swift 4 允许您创建字典值的组。
var cities = ["Delhi","Bangalore","Hyderabad","Dehradun","Bihar"]
您可以使用以下简单语法根据第一个字母对字典的值进行分组。
var GroupedCities = Dictionary(grouping: cities ) { $0.first! }
以上代码的结果将是
["D" :["Delhi","Dehradun"], "B" : ["Bengaluru","Bihar"], "H" : ["Hyderabad"]]
访问字典
您可以使用下标语法从字典中检索值,在字典名称后立即使用方括号传递要检索的值的键,如下所示:
var someVar = someDict[key]
让我们检查以下示例以创建、初始化和访问字典中的值:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"] var someVar = someDict[1] print( "Value of key = 1 is \(someVar)" ) print( "Value of key = 2 is \(someDict[2])" ) print( "Value of key = 3 is \(someDict[3])" )
当上述代码编译并执行时,会产生以下结果:
Value of key = 1 is Optional("One") Value of key = 2 is Optional("Two") Value of key = 3 is Optional("Three")
修改字典
您可以使用 **updateValue(forKey:)** 方法将现有值添加到字典的给定键。此方法返回字典值类型的可选值。这是一个简单的示例:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"] var oldVal = someDict.updateValue("New value of one", forKey: 1) var someVar = someDict[1] print( "Old value of key = 1 is \(oldVal)" ) print( "Value of key = 1 is \(someVar)" ) print( "Value of key = 2 is \(someDict[2])" ) print( "Value of key = 3 is \(someDict[3])" )
当上述代码编译并执行时,会产生以下结果:
Old value of key = 1 is Optional("One") Value of key = 1 is Optional("New value of one") Value of key = 2 is Optional("Two") Value of key = 3 is Optional("Three")
您可以通过在给定键处分配新值来修改字典的现有元素,如以下示例所示:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"] var oldVal = someDict[1] someDict[1] = "New value of one" var someVar = someDict[1] print( "Old value of key = 1 is \(oldVal)" ) print( "Value of key = 1 is \(someVar)" ) print( "Value of key = 2 is \(someDict[2])" ) print( "Value of key = 3 is \(someDict[3])" )
当上述代码编译并执行时,会产生以下结果:
Old value of key = 1 is Optional("One") Value of key = 1 is Optional("New value of one") Value of key = 2 is Optional("Two") Value of key = 3 is Optional("Three")
删除键值对
您可以使用 **removeValueForKey()** 方法从字典中删除键值对。如果存在,此方法将删除键值对并返回删除的值,或者如果不存在值,则返回 nil。这是一个简单的示例:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"] var removedValue = someDict.removeValue(forKey: 2) print( "Value of key = 1 is \(someDict[1])" ) print( "Value of key = 2 is \(someDict[2])" ) print( "Value of key = 3 is \(someDict[3])" )
当上述代码编译并执行时,会产生以下结果:
Value of key = 1 is Optional("One") Value of key = 2 is nil Value of key = 3 is Optional("Three")
您还可以使用下标语法通过为该键分配 **nil** 值来从字典中删除键值对。这是一个简单的示例:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"] someDict[2] = nil print( "Value of key = 1 is \(someDict[1])" ) print( "Value of key = 2 is \(someDict[2])" ) print( "Value of key = 3 is \(someDict[3])" )
当上述代码编译并执行时,会产生以下结果:
Value of key = 1 is Optional("One") Value of key = 2 is nil Value of key = 3 is Optional("Three")
遍历字典
您可以使用 **for-in** 循环遍历字典中所有键值对,如以下示例所示:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"] for (index, keyValue) in someDict.enumerated() { print("Dictionary key \(index) - Dictionary value \(keyValue)") }
当上述代码编译并执行时,会产生以下结果:
Dictionary key 2 - Dictionary value Two Dictionary key 3 - Dictionary value Three Dictionary key 1 - Dictionary value One
您可以使用 **enumerate()** 函数,该函数返回项目的索引及其(键,值)对,如下面的示例所示:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"] for (key, value) in someDict.enumerated() { print("Dictionary key \(key) - Dictionary value \(value)") }
当上述代码编译并执行时,会产生以下结果:
Dictionary key 0 - Dictionary value (key: 2, value: "Two") Dictionary key 1 - Dictionary value (key: 3, value: "Three") Dictionary key 2 - Dictionary value (key: 1, value: "One")
转换为数组
您可以从给定字典中提取键值对列表,为键和值分别构建单独的数组。这是一个示例:
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"] let dictKeys = [Int](someDict.keys) let dictValues = [String](someDict.values) print("Print Dictionary Keys") for (key) in dictKeys { print("\(key)") } print("Print Dictionary Values") for (value) in dictValues { print("\(value)") }
当上述代码编译并执行时,会产生以下结果:
Print Dictionary Keys 2 3 1 Print Dictionary Values Two Three One
count 属性
您可以使用字典的只读 **count** 属性来查找字典中的项目数量,如下所示:
var someDict1:[Int:String] = [1:"One", 2:"Two", 3:"Three"] var someDict2:[Int:String] = [4:"Four", 5:"Five"] print("Total items in someDict1 = \(someDict1.count)") print("Total items in someDict2 = \(someDict2.count)")
当上述代码编译并执行时,会产生以下结果:
Total items in someDict1 = 3 Total items in someDict2 = 2
empty 属性
您可以使用字典的只读 **empty** 属性来确定字典是否为空,如下所示:
var someDict1:[Int:String] = [1:"One", 2:"Two", 3:"Three"] var someDict2:[Int:String] = [4:"Four", 5:"Five"] var someDict3:[Int:String] = [Int:String]() print("someDict1 = \(someDict1.isEmpty)") print("someDict2 = \(someDict2.isEmpty)") print("someDict3 = \(someDict3.isEmpty)")
当上述代码编译并执行时,会产生以下结果:
someDict1 = false someDict2 = false someDict3 = true
Swift - 函数
函数是一组组织在一起执行特定任务的语句。Swift 4 函数可以像简单的 C 函数一样简单,也可以像 Objective C 语言函数一样复杂。它允许我们在函数调用中传递局部和全局参数值。
**函数声明** - 告诉编译器函数的名称、返回类型和参数。
**函数定义** - 它提供函数的实际主体。
Swift 4 函数包含参数类型及其返回类型。
函数定义
在 Swift 4 中,函数由“func”关键字定义。当新定义函数时,它可以将一个或多个值作为输入“参数”传递给函数,它将在主体中处理函数并将值作为输出“返回类型”传递回函数。
每个函数都有一个函数名,描述了函数执行的任务。要使用函数,您需要“调用”该函数及其名称,并传递与函数参数类型匹配的输入值(称为参数)。函数参数也称为“元组”。
函数参数必须始终以与函数参数列表相同的顺序提供,返回值后跟 →。
语法
func funcname(Parameters) -> returntype { Statement1 Statement2 --- Statement N return parameters }
请查看以下代码。学生的姓名声明为在函数“student”中声明的字符串数据类型,当调用函数时,它将返回学生的姓名。
func student(name: String) -> String { return name } print(student(name: "First Program")) print(student(name: "About Functions"))
当我们使用游乐场运行上述程序时,会得到以下结果:
First Program About Functions
调用函数
假设我们定义了一个名为“display”的函数来考虑例如显示数字,一个名为“display”的函数首先初始化为参数“no1”,它持有整数数据类型。然后将参数“no1”分配给参数“a”,此后“a”将指向相同的整数数据类型。现在参数“a”被返回到函数。这里 display() 函数将持有整数值并在每次调用函数时返回整数值。
func display(no1: Int) -> Int { let a = no1 return a } print(display(no1: 100)) print(display(no1: 200))
当我们使用 playground 运行以上程序时,我们将得到以下结果:
100 200
参数和返回值
Swift 4 提供了灵活的函数参数及其从简单到复杂值的返回值。与 C 和 Objective C 类似,Swift 4 中的函数也可以采用多种形式。
带参数的函数
通过将参数值传递给函数主体来访问函数。我们可以将单个到多个参数值作为元组传递到函数内部。
func mult(no1: Int, no2: Int) -> Int { return no1*no2 } print(mult(no1: 2, no2: 20)) print(mult(no1: 3, no2: 15)) print(mult(no1: 4, no2: 30))
当我们使用 playground 运行以上程序时,我们将得到以下结果:
40 45 120
无参数的函数
我们也可以拥有没有任何参数的函数。
语法
func funcname() -> datatype { return datatype }
以下是一个没有参数的函数示例:
func votersname() -> String { return "Alice" } print(votersname())
当我们使用游乐场运行上述程序时,会得到以下结果:
Alice
带返回值的函数
函数也用于返回字符串、整数和浮点数数据类型的值作为返回值。为了找到给定数组中最大和最小的数字,声明了一个名为“ls”的函数,并使用大的和小的整数数据类型。
初始化一个数组以保存整数值。然后处理数组,读取并比较数组中每个值与其前一个值。当值小于前一个值时,将其存储在“small”参数中,否则将其存储在“large”参数中,并通过调用函数返回这些值。
func ls(array: [Int]) -> (large: Int, small: Int) { var lar = array[0] var sma = array[0] for i in array[1..<array.count] { if i < sma { sma = i } else if i > lar { lar = i } } return (lar, sma) } let num = ls(array: [40,12,-5,78,98]) print("Largest number is: \(num.large) and smallest number is: \(num.small)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Largest number is: 98 and smallest number is: -5
无返回值的函数
某些函数可能在函数内部声明参数,但没有任何返回值。以下程序将a和b声明为sum()函数的参数。在函数本身内部,通过调用函数调用sum()传递参数a和b的值,并打印其值,从而消除了返回值。
func sum(a: Int, b: Int) { let a = a + b let b = a - b print(a, b) } sum(a: 20, b: 10) sum(a: 40, b: 10) sum(a: 24, b: 6)
当我们使用游乐场运行上述程序时,会得到以下结果:
30 20 50 40 30 24
具有可选返回值类型的函数
Swift 4引入了“可选”功能,通过引入安全措施来解决问题。例如,假设我们正在声明函数值的返回值类型为整数,但如果函数返回字符串值或空值会发生什么?在这种情况下,编译器将返回错误值。“可选”是为了解决这些问题而引入的。
可选函数将采用两种形式:“值”和“nil”。我们将使用关键保留字符“?”来提及“可选”,以检查元组是否返回一个值或一个空值。
func minMax(array: [Int]) -> (min: Int, max: Int)? { if array.isEmpty { return nil } var currentMin = array[0] var currentMax = array[0] for value in array[1..<array.count] { if value < currentMin { currentMin = value } else if value > currentMax { currentMax = value } } return (currentMin, currentMax) } if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) { print("min is \(bounds.min) and max is \(bounds.max)") }
当我们在游乐场中运行上述程序时,将得到以下结果:
min is -6 and max is 109
“可选”用于检查“nil”或垃圾值,从而在调试中消耗大量时间,并使代码对用户高效且易读。
函数局部参数名与外部参数名
局部参数名
局部参数名仅在函数内部访问。
func sample(number: Int) { print(number) }
这里,func sample参数编号被声明为内部变量,因为它由函数sample()在内部访问。这里“number”被声明为局部变量,但对变量的引用是在函数外部使用以下语句进行的:
func sample(number: Int) { print(number) } sample(number: 1) sample(number: 2) sample(number: 3)
当我们使用游乐场运行上述程序时,会得到以下结果:
1 2 3
外部参数名
外部参数名允许我们为函数参数命名,以使它们的用途更清晰。例如,您可以在下面命名两个函数参数,然后如下调用该函数:
func pow(firstArg a: Int, secondArg b: Int) -> Int { var res = a for _ in 1..<b { res = res * a } print(res) return res } pow(firstArg:5, secondArg:3)
当我们使用游乐场运行上述程序时,会得到以下结果:
125
可变参数
当我们想定义具有多个参数的函数时,我们可以将成员声明为“可变”参数。参数可以通过参数名称后的(···)指定为可变参数。
func vari<N>(members: N...){ for i in members { print(i) } } vari(members: 4,3,5) vari(members: 4.5, 3.1, 5.6) vari(members: "Swift 4", "Enumerations", "Closures")
当我们使用游乐场运行上述程序时,会得到以下结果:
4 3 5 4.5 3.1 5.6 Swift 4 Enumerations Closures
常量、变量和I/O参数
函数默认将参数视为“常量”,而用户也可以将参数声明为变量。我们已经讨论过“let”关键字用于声明常量参数,而变量参数则使用“var”关键字定义。
Swift 4中的I/O参数提供了一种功能,即使在函数调用后修改了参数值,也可以保留这些参数值。在函数参数定义的开头,声明“inout”关键字以保留成员值。
它派生关键字“inout”,因为其值被“传入”函数,其值由函数体访问和修改,并“传出”函数以修改原始参数。
变量仅作为输入输出参数的参数传递,因为其值仅在函数内部和外部修改。因此,无需将字符串和文字声明为输入输出参数。变量名前的“&”表示我们将参数传递给输入输出参数。
func temp(a1: inout Int, b1: inout Int) { let t = a1 a1 = b1 b1 = t } var no = 2 var co = 10 temp(a1: &no, b1: &co) print("Swapped values are \(no), \(co)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Swapped values are 10, 2
函数类型及其用法
每个函数都遵循特定的函数,通过考虑输入参数并输出期望的结果。
func inputs(no1: Int, no2: Int) -> Int { return no1/no2 }
以下是一个示例:
func inputs(no1: Int, no2: Int) -> Int { return no1/no2 } print(inputs(no1: 20, no2: 10)) print(inputs(no1: 36, no2: 6))
当我们使用游乐场运行上述程序时,会得到以下结果:
2 6
这里,函数用两个参数no1和no2初始化为整数数据类型,其返回值类型也声明为“int”。
Func inputstr(name: String) -> String { return name }
这里,函数被声明为string数据类型。
函数也可以具有void数据类型,并且此类函数不会返回任何内容。
func inputstr() { print("Swift 4 Functions") print("Types and its Usage") } inputstr()
当我们使用游乐场运行上述程序时,会得到以下结果:
Swift 4 Functions Types and its Usage
上述函数被声明为一个无参数且无返回值的void函数。
使用函数类型
函数首先传递整数、浮点数或字符串类型参数,然后将其作为常量或变量传递给函数,如下所示。
var addition: (Int, Int) -> Int = sum
这里sum是一个具有“a”和“b”整数变量的函数名,现在将其声明为函数名addition的变量。此后,addition和sum函数都具有相同数量的参数,声明为整数数据类型,并将整数返回值作为引用。
func sum(a: Int, b: Int) -> Int { return a + b } var addition: (Int, Int) -> Int = sum print("Result: \(addition(40, 89))")
当我们使用游乐场运行上述程序时,会得到以下结果:
Result: 129
函数类型作为参数类型和返回值类型
我们还可以将函数本身作为参数类型传递给另一个函数。
func sum(a: Int, b: Int) -> Int { return a + b } var addition: (Int, Int) -> Int = sum print("Result: \(addition(40, 89))") func another(addition: (Int, Int) -> Int, a: Int, b: Int) { print("Result: \(addition(a, b))") } another(sum, 10, 20)
当我们使用游乐场运行上述程序时,会得到以下结果:
Result: 129 Result: 30
嵌套函数
嵌套函数提供了通过调用内部函数来调用外部函数的功能。
func calcDecrement(forDecrement total: Int) -> () -> Int { var overallDecrement = 0 func decrementer() -> Int { overallDecrement -= total return overallDecrement } return decrementer } let decrem = calcDecrement(forDecrement: 30) print(decrem())
当我们使用游乐场运行上述程序时,会得到以下结果:
-30
Swift - 闭包
Swift 4中的闭包类似于自包含函数,这些函数被组织成块,并且可以在任何地方调用,就像C和Objective C语言一样。在函数内部定义的常量和变量引用被捕获并存储在闭包中。函数被视为闭包的特例,它采用以下三种形式:
全局函数 | 嵌套函数 | 闭包表达式 |
---|---|---|
有名。不捕获任何值 | 有名。捕获来自封闭函数的值 | 未命名的闭包捕获来自相邻块的值 |
Swift 4语言中的闭包表达式遵循简洁、优化和轻量级语法风格,其中包括。
- 从上下文中推断参数和返回值类型。
- 从单表达式闭包中隐式返回。
- 简写参数名称和
- 尾随闭包语法
语法
以下是一个定义接受参数并返回数据类型的闭包的通用语法:
{ (parameters) −> return type in statements }
以下是一个简单的示例:
let studname = { print("Welcome to Swift Closures") } studname()
当我们使用游乐场运行上述程序时,会得到以下结果:
Welcome to Swift Closures
以下闭包接受两个参数并返回一个Bool值:
{ (Int, Int) −> Bool in Statement1 Statement 2 --- Statement n }
以下是一个简单的示例:
let divide = { (val1: Int, val2: Int) -> Int in return val1 / val2 } let result = divide(200, 20) print (result)
当我们使用游乐场运行上述程序时,会得到以下结果:
10
闭包中的表达式
嵌套函数提供了一种命名和定义代码块的便捷方法。而不是表示整个函数声明和名称,构造用于表示较短的函数。通过闭包表达式实现了用清晰简洁的语句和集中的语法表示函数。
升序程序
字符串排序是通过Swift 4的关键保留函数“sorted”实现的,该函数已在标准库中可用。该函数将按升序对给定的字符串进行排序,并将元素存储在一个新数组中,该数组具有与旧数组中提到的相同的大小和数据类型。旧数组保持不变。
在sorted函数内部表示两个参数:
表示为数组的已知类型的值。
数组内容(Int,Int)并返回一个布尔值(Bool),如果数组已正确排序,它将返回true值,否则将返回false。
编写一个带有输入字符串的普通函数并将其传递给sorted函数,以使字符串按排序到新数组中,如下所示:
func ascend(s1: String, s2: String) -> Bool { return s1 > s2 } let stringcmp = ascend(s1: "Swift 4", s2: "great") print (stringcmp)
当我们在游乐场中运行上述程序时,将得到以下结果:
true
要为冰淇淋排序的初始数组给出为“Swift 4”和“great”。用于排序数组的函数被声明为字符串数据类型,其返回值类型被提及为布尔型。两个字符串都被比较并按升序排序并存储在一个新数组中。如果排序成功执行,则函数将返回true值,否则将返回false。
闭包表达式语法使用:
- 常量参数,
- 变量参数,以及
- 输入输出参数。
闭包表达式不支持默认值。可变参数和元组也可以用作参数类型和返回值类型。
let sum = { (no1: Int, no2: Int) -> Int in return no1 + no2 } let digits = sum(10, 20) print(digits)
当我们使用游乐场运行上述程序时,会得到以下结果:
30
函数语句中提到的参数和返回值类型声明也可以通过使用“in”关键字的内联闭包表达式函数表示。一旦声明了参数和返回值类型,“in”关键字用于表示闭包的主体。
单表达式隐式返回
这里,sorted函数的第二个参数的函数类型清楚地表明闭包必须返回一个Bool值。因为闭包的主体包含一个返回Bool值的单一表达式(s1 > s2),所以没有歧义,并且可以省略return关键字。
要在表达式闭包中返回单个表达式语句,在声明部分省略“return”关键字。
var count:[Int] = [5, 10, -6, 75, 20] let descending = count.sorted(by: { n1, n2 in n1 > n2 }) let ascending = count.sorted(by: { n1, n2 in n1 < n2 }) print(descending) print(ascending)
当我们使用游乐场运行上述程序时,会得到以下结果:
[75, 20, 10, 5, -6] [-6, 5, 10, 20, 75]
语句本身清楚地定义了当字符串1大于字符串2时返回true,否则返回false,因此这里省略了return语句。
已知类型闭包
考虑两个数字的加法。我们知道加法将返回整数数据类型。因此,已知类型闭包声明为:
let sub = { (no1: Int, no2: Int) -> Int in return no1 - no2 } let digits = sub(10, 20) print(digits)
当我们使用游乐场运行上述程序时,会得到以下结果:
-10
将简写参数名称声明为闭包
Swift 4自动为内联闭包提供简写参数名称,可以使用这些名称通过名称$0、$1、$2等来引用闭包参数的值。
var shorthand: (String, String) -> String shorthand = { $1 } print(shorthand("100", "200"))
这里,$0和$1分别指代闭包的第一个和第二个String参数。
当我们使用游乐场运行上述程序时,会得到以下结果:
200
Swift 4便于用户通过表示$0、$1、$2 --- $n来表示内联闭包作为简写参数名称。
当我们在闭包表达式内部表示简写参数名称时,闭包参数列表在定义部分被省略。根据函数类型,将派生简写参数名称。由于简写参数是在表达式主体中定义的,因此省略了“in”关键字。
闭包作为运算符函数
Swift 4提供了一种简单的方法来访问成员,只需提供闭包作为运算符函数即可。在前面的示例中,关键字“Bool”用于返回字符串相等时返回“true”,否则返回“false”。
表达式通过闭包中的运算符函数变得更加简单,如下所示:
let numb = [98, -20, -30, 42, 18, 35] var sortedNumbers = numb.sorted ({ (left: Int, right: Int) -> Bool in return left < right }) let asc = numb.sorted(<) print(asc)
当我们使用游乐场运行上述程序时,会得到以下结果:
[-30, -20, 18, 35, 42, 98]
闭包作为尾随闭包
将函数的最终参数传递给闭包表达式是通过“尾随闭包”的帮助来声明的。它写在函数()外部,并带有{}。当无法在一行中内联编写函数时,需要使用它。
reversed = sorted(names) { $0 > $1}
其中{$0 > $1}表示为在(names)外部声明的尾随闭包。
import Foundation var letters = ["North", "East", "West", "South"] let twoletters = letters.map({ (state: String) -> String in return state.substringToIndex(advance(state.startIndex, 2)).uppercaseString }) let stletters = letters.map() { $0.substringToIndex(advance($0.startIndex, 2)).uppercaseString } print(stletters)
当我们使用游乐场运行上述程序时,会得到以下结果:
[NO, EA, WE, SO]
捕获值和引用类型
在Swift 4中,捕获常量和变量值是借助闭包完成的。它进一步引用和修改闭包主体中这些常量和变量的值,即使变量不再存在。
捕获常量和变量值是通过使用嵌套函数在其他函数的主体中编写函数来实现的。
嵌套函数捕获:
- 外部函数参数。
- 捕获在外部函数内定义的常量和变量。
在Swift 4中,当在函数内部声明常量或变量时,闭包也会自动创建对该变量的引用。它还提供了一种在同一个闭包中引用多个变量的功能,如下所示:
let decrem = calcDecrement(forDecrement: 18) decrem()
这里oneDecrement和Decrement变量都将指向同一个内存块作为闭包引用。
func calcDecrement(forDecrement total: Int) -> () -> Int { var overallDecrement = 100 func decrementer() -> Int { overallDecrement -= total print(overallDecrement) return overallDecrement } return decrementer } let decrem = calcDecrement(forDecrement: 18) decrem() decrem() decrem()
当我们使用游乐场运行上述程序时,会得到以下结果:
82 64 46
每次调用外部函数calcDecrement时,它都会调用decrementer()函数并将值减去18,并借助外部函数calcDecrement返回结果。这里calcDecrement充当闭包。
即使函数 `decrementer()` 没有参数,闭包默认也会通过捕获其现有值来引用变量 `overallDecrement` 和 `total`。指定变量的值副本与新的 `decrementer()` 函数一起存储。Swift 4 通过在变量未使用时分配和释放内存空间来处理内存管理函数。
Swift - 枚举
枚举是一种用户定义的数据类型,它包含一组相关的值。关键字 **enum** 用于定义枚举数据类型。
枚举功能
Swift 4 中的枚举也类似于 C 和 Objective C 的结构。
它在类中声明,其值可以通过该类的实例访问。
初始成员值使用枚举初始化器定义。
通过确保标准协议功能来扩展其功能。
语法
枚举以 `enum` 关键字引入,并将它们的整个定义放在一对大括号内 -
enum enumname { // enumeration values are described here }
例如,您可以为一周中的日期定义一个枚举,如下所示 -
enum DaysofaWeek { case Sunday case Monday --- case Saturday }
示例
enum names { case Swift case Closures } var lang = names.Closures lang = .Closures switch lang { case .Swift: print("Welcome to Swift") case .Closures: print("Welcome to Closures") default: print("Introduction") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Welcome to Closures
Swift 4 枚举不会像 C 和 Objective C 一样为其成员分配默认值。相反,成员由其枚举名称显式定义。枚举名称应以大写字母开头(例如:`enum DaysofaWeek`)。
var weekDay = DaysofaWeek.Sunday
这里,枚举名称 `DaysofaWeek` 被分配给变量 `weekday.Sunday`。它通知编译器,属于 `Sunday` 的数据类型将被分配给该特定类的后续枚举成员。一旦定义了枚举成员数据类型,就可以通过传递值和进一步计算来访问这些成员。
带有 Switch 语句的枚举
Swift 4 的 `Switch` 语句也遵循多路选择。根据指定的条件,每次只访问一个变量。`switch` 语句中的 `default` 情况用于捕获未指定的案例。
enum Climate { case India case America case Africa case Australia } var season = Climate.America season = .America switch season { case .India: print("Climate is Hot") case .America: print("Climate is Cold") case .Africa: print("Climate is Moderate") case .Australia: print("Climate is Rainy") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Climate is Cold
程序首先将 `Climate` 定义为枚举名称。然后声明其成员(如 `India`、`America`、`Africa` 和 `Australia`)属于类 `Climate`。现在,成员 `America` 被分配给一个 `Season` 变量。此外,`Switch` 情况将查看对应于 `.America` 的值,并将分支到该特定语句。输出将显示为“Climate is Cold”。同样,所有成员都可以通过 `switch` 语句访问。当条件不满足时,它默认打印“Climate is not predictable”。
枚举可以进一步分类为关联值和原始值。
关联值和原始值的区别
关联值 | 原始值 |
不同的数据类型 | 相同的数据类型 |
例如:`enum {10,0.8,"Hello"}` | 例如:`enum {10,35,50}` |
基于常量或变量创建值 | 预填充的值 |
每次声明时都可能变化 | 成员的值相同 |
带有关联值的枚举
enum Student { case Name(String) case Mark(Int,Int,Int) } var studDetails = Student.Name("Swift 4") var studMarks = Student.Mark(98,97,95) switch studMarks { case .Name(let studName): print("Student name is: \(studName).") case .Mark(let Mark1, let Mark2, let Mark3): print("Student Marks are: \(Mark1),\(Mark2),\(Mark3).") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Student Marks are: 98,97,95.
例如,要访问学生的姓名和三门科目获得的分数,枚举名称声明为 `student`,枚举类中存在的成员是属于字符串数据类型的 `name`,分数表示为数据类型为整数的 `mark1`、`mark2` 和 `mark3`。要访问学生的姓名或他们获得的分数
var studDetails = Student.Name("Swift") var studMarks = Student.Mark(98,97,95)
现在,`switch` 情况将打印学生姓名(如果执行该情况块),否则将打印学生获得的分数。如果这两个条件都失败,则将执行默认块。
带有原始值的枚举
原始值可以是字符串、字符或任何整数或浮点数类型。每个原始值在其枚举声明中必须是唯一的。当将整数用于原始值时,如果某些枚举成员未指定值,则它们会自动递增。
enum Month: Int { case January = 1, February, March, April, May, June, July, August, September, October, November, December } let yearMonth = Month.May.rawValue print("Value of the Month is: \(yearMonth).")
当我们使用游乐场运行上述程序时,会得到以下结果:
Value of the Month is: 5.
Swift - 结构体
Swift 4 提供了一个灵活的构建块,用于利用结构作为构造。通过使用这些结构,可以定义构造方法和属性。
与 C 和 Objective C 不同
结构不需要实现文件和接口。
结构允许我们创建一个单个文件,并自动将其接口扩展到其他块。
在结构中,变量值被复制并在后续代码中通过返回旧值的副本传递,以便无法更改这些值。
语法
Structures are defined with a 'Struct' Keyword. struct nameStruct { Definition 1 Definition 2 --- Definition N }
结构的定义
例如,假设我们必须访问包含三门科目分数的学生记录并找出三门科目的总分。这里 `markStruct` 用于初始化一个结构,其中三个分数的数据类型为 `Int`。
struct MarkStruct { var mark1: Int var mark2: Int var mark3: Int }
访问结构及其属性
结构的成员通过其结构名称访问。结构的实例由 `let` 关键字初始化。
struct studentMarks { var mark1 = 100 var mark2 = 200 var mark3 = 300 } let marks = studentMarks() print("Mark1 is \(marks.mark1)") print("Mark2 is \(marks.mark2)") print("Mark3 is \(marks.mark3)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Mark1 is 100 Mark2 is 200 Mark3 is 300
学生分数通过结构名称 `studentMarks` 访问。结构成员初始化为 `mark1`、`mark2`、`mark3`,其值为整数类型。然后将结构 `studentMarks()` 传递给带有 `let` 关键字的 `marks`。此后,`marks` 将包含结构成员值。现在,通过使用 `.` 和其初始化名称访问结构成员值来打印这些值。
struct MarksStruct { var mark: Int init(mark: Int) { self.mark = mark } } var aStruct = MarksStruct(mark: 98) var bStruct = aStruct // aStruct and bStruct are two structs with the same value! bStruct.mark = 97 print(aStruct.mark) // 98 print(bStruct.mark) // 97
当我们使用游乐场运行上述程序时,会得到以下结果:
98 97
结构的最佳使用实践
Swift 4 语言提供了将结构定义为自定义数据类型以构建函数块的功能。结构的实例按其值传递到定义的块中以进行进一步操作。
需要结构的原因
封装简单数据值。
通过“值”而不是“引用”复制封装的数据及其关联属性。
结构到“复制”和“引用”。
Swift 4 中的结构通过其值而不是通过其引用传递其成员。
struct markStruct { var mark1: Int var mark2: Int var mark3: Int init(mark1: Int, mark2: Int, mark3: Int) { self.mark1 = mark1 self.mark2 = mark2 self.mark3 = mark3 } } var marks = markStruct(mark1: 98, mark2: 96, mark3:100) print(marks.mark1) print(marks.mark2) print(marks.mark3)
当我们使用游乐场运行上述程序时,会得到以下结果:
98 96 100
另一个例子
struct markStruct { var mark1: Int var mark2: Int var mark3: Int init(mark1: Int, mark2: Int, mark3: Int) { self.mark1 = mark1 self.mark2 = mark2 self.mark3 = mark3 } } var fail = markStruct(mark1: 34, mark2: 42, mark3: 13) print(fail.mark1) print(fail.mark2) print(fail.mark3)
当我们使用游乐场运行上述程序时,会得到以下结果:
34 42 13
首先定义结构 `markStruct` 及其成员 `mark1`、`mark2` 和 `mark3`。现在,成员类的变量被初始化为保存整数值。然后使用 `self` 关键字创建结构成员的副本。一旦创建了结构成员的副本,将带有参数 `marks` 的结构块传递给 `marks` 变量,该变量现在将保存学生的分数。然后分数打印为 98、96、100。下一步,对于相同的结构成员,另一个名为 `fail` 的实例用于指向具有不同分数的相同结构成员。然后结果现在打印为 34、42、13。这清楚地解释了结构将拥有成员变量的副本,然后将成员传递到其即将到来的函数块。
Swift - 类
Swift 4 中的类是灵活构造的构建块。类似于常量、变量和函数,用户可以定义类属性和方法。Swift 4 为我们提供了这样的功能:在声明类时,用户无需创建接口或实现文件。Swift 4 允许我们将类创建为单个文件,并且一旦类初始化,将默认创建外部接口。
拥有类的益处
继承将一个类的属性获取到另一个类
类型转换使用户能够在运行时检查类类型
析构器负责释放内存资源
引用计数允许类实例具有多个引用
类和结构的共同特征
- 属性定义为存储值
- 下标定义为提供对值的访问
- 方法初始化以改进功能
- 初始状态由初始化器定义
- 功能扩展到默认值之外
- 确认协议功能标准
语法
Class classname { Definition 1 Definition 2 --- Definition N }
类定义
class student { var studname: String var mark: Int var mark2: Int }
创建实例的语法
let studrecord = student()
示例
class MarksStruct { var mark: Int init(mark: Int) { self.mark = mark } } class studentMarks { var mark = 300 } let marks = studentMarks() print("Mark is \(marks.mark)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Mark is 300
作为引用类型访问类属性
类属性可以通过 `.` 语法访问。属性名称在实例名称后面用 `.` 分隔。
class MarksStruct { var mark: Int init(mark: Int) { self.mark = mark } } class studentMarks { var mark1 = 300 var mark2 = 400 var mark3 = 900 } let marks = studentMarks() print("Mark1 is \(marks.mark1)") print("Mark2 is \(marks.mark2)") print("Mark3 is \(marks.mark3)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Mark1 is 300 Mark2 is 400 Mark3 is 900
类恒等运算符
Swift 4 中的类指的是多个指向单个实例的常量和变量。要了解指向特定类实例的常量和变量,可以使用恒等运算符。类实例始终通过引用传递。在类中,`NSString`、`NSArray` 和 `NSDictionary` 实例始终被分配并作为对现有实例的引用传递,而不是作为副本。
相同运算符 | 不相同运算符 |
---|---|
使用的运算符为 (===) | 使用的运算符为 (!==) |
当两个常量或变量指向同一个实例时返回 `true` | 当两个常量或变量指向不同的实例时返回 `true` |
class SampleClass: Equatable { let myProperty: String init(s: String) { myProperty = s } } func ==(lhs: SampleClass, rhs: SampleClass) -> Bool { return lhs.myProperty == rhs.myProperty } let spClass1 = SampleClass(s: "Hello") let spClass2 = SampleClass(s: "Hello") spClass1 === spClass2 // false print("\(spClass1)") spClass1 !== spClass2 // true print("\(spClass2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
main.SampleClass main.SampleClass
Swift - 属性
Swift 4 语言为类、枚举或结构提供属性来关联值。属性可以进一步分类为存储属性和计算属性。
存储属性和计算属性的区别
存储属性 | 计算属性 |
---|---|
将常量和变量值存储为实例 | 计算值而不是存储值 |
由类和结构提供 | 由类、枚举和结构提供 |
存储属性和计算属性都与实例类型相关联。当属性与其类型值相关联时,则将其定义为“类型属性”。存储属性和计算属性通常与特定类型的实例相关联。但是,属性也可以与类型本身相关联。此类属性称为类型属性。属性观察器也用于
- 观察存储属性的值
- 观察从超类派生的继承子类的属性
存储属性
Swift 4 引入了存储属性的概念来存储常量和变量的实例。常量的存储属性由 `let` 关键字定义,变量的存储属性由 `var` 关键字定义。
- 在定义期间,存储属性提供“默认值”
- 在初始化期间,用户可以初始化和修改初始值
struct Number { var digits: Int let pi = 3.1415 } var n = Number(digits: 12345) n.digits = 67 print("\(n.digits)") print("\(n.pi)")
当我们使用游乐场运行上述程序时,会得到以下结果:
67 3.1415
考虑上面代码中的以下行 -
let pi = 3.1415
这里,变量 `pi` 初始化为具有实例 `pi = 3.1415` 的存储属性值。因此,无论何时引用该实例,它都将仅保存值 3.1415。
另一种拥有存储属性的方法是将其作为常量结构。因此,结构的整个实例将被视为“常量的存储属性”。
struct Number { var digits: Int let numbers = 3.1415 } var n = Number(digits: 12345) n.digits = 67 print("\(n.digits)") print("\(n.numbers)") n.numbers = 8.7
当我们使用游乐场运行上述程序时,会得到以下结果:
error: cannot assign to 'numbers' in 'n' n.numbers = 8.7
它不会将 `number` 重新初始化为 8.7,而是会返回一条错误消息,指示 `number` 被声明为常量。
延迟存储属性
Swift 4 提供了一个灵活的属性,称为“延迟存储属性”,它不会在变量第一次初始化时计算初始值。`lazy` 修饰符用于变量声明之前,以将其作为延迟存储属性。
延迟属性用于 -
- 延迟对象创建。
- 当属性依赖于类的其他部分时,这些部分尚不清楚
class sample { lazy var no = number() // `var` declaration is required. } class number { var name = "Swift 4" } var firstsample = sample() print(firstsample.no.name)
当我们使用游乐场运行上述程序时,会得到以下结果:
Swift 4
实例变量
在 Objective C 中,存储属性还具有实例变量作为备份目的,以存储在存储属性中声明的值。
Swift 4 将这两个概念集成到单个“存储属性”声明中。而不是具有相应的实例变量和备份值,“存储属性”包含在单个位置定义的有关变量属性的所有集成信息,这些信息由变量名称、数据类型和内存管理功能定义。
计算属性
计算属性不是存储值,而是提供 getter 和可选 setter 以间接检索和设置其他属性和值。
class sample { var no1 = 0.0, no2 = 0.0 var length = 300.0, breadth = 150.0 var middle: (Double, Double) { get { return (length / 2, breadth / 2) } set(axis){ no1 = axis.0 - (length / 2) no2 = axis.1 - (breadth / 2) } } } var result = sample() print(result.middle) result.middle = (0.0, 10.0) print(result.no1) print(result.no2)
当我们使用游乐场运行上述程序时,会得到以下结果:
(150.0, 75.0) -150.0 -65.0
当计算属性将新值保留为未定义时,将为该特定变量设置默认值。
计算属性作为只读属性
计算属性中的只读属性定义为具有 getter 但没有 setter 的属性。它始终用于返回值。变量通过 `.` 语法进一步访问,但不能设置为另一个值。
class film { var head = "" var duration = 0.0 var metaInfo: [String:String] { return [ "head": self.head, "duration":"\(self.duration)" ] } } var movie = film() movie.head = "Swift 4 Properties" movie.duration = 3.09 print(movie.metaInfo["head"]!) print(movie.metaInfo["duration"]!)
当我们使用游乐场运行上述程序时,会得到以下结果:
Swift 4 Properties 3.09
计算属性作为属性观察器
在 Swift 4 中,要观察和响应属性值,可以使用属性观察器。每次设置属性值时都会调用属性观察器。除了延迟存储属性外,我们还可以通过方法“覆盖”向“继承”属性添加属性观察器。
属性观察器可以通过以下任一方式定义
在存储值之前 - `willset`
在存储新值之后 - `didset`
当在初始化器中设置属性时,不会调用 `willset` 和 `didset` 观察器。
class Samplepgm { var counter: Int = 0 { willSet(newTotal){ print("Total Counter is: \(newTotal)") } didSet { if counter > oldValue { print("Newly Added Counter \(counter - oldValue)") } } } } let NewCounter = Samplepgm() NewCounter.counter = 100 NewCounter.counter = 800
当我们使用游乐场运行上述程序时,会得到以下结果:
Total Counter is: 100 Newly Added Counter 100 Total Counter is: 800 Newly Added Counter 700
局部变量和全局变量
声明局部变量和全局变量用于计算和观察属性。
局部变量 | 全局变量 |
---|---|
在函数、方法或闭包上下文中定义的变量。 | 在函数、方法、闭包或类型上下文之外定义的变量。 |
用于存储和检索值。 | 用于存储和检索值。 |
存储属性用于获取和设置值。 | 存储属性用于获取和设置值。 |
计算属性也用于此目的。 | 计算属性也用于此目的。 |
类型属性
属性在类型定义部分用花括号 {} 定义,变量的作用域也在之前定义。对于值类型的类型属性定义,使用“static”关键字;对于类类型,使用“class”关键字。
语法
struct Structname { static var storedTypeProperty = " " static var computedTypeProperty: Int { // return an Int value here } } enum Enumname { static var storedTypeProperty = " " static var computedTypeProperty: Int { // return an Int value here } } class Classname { class var computedTypeProperty: Int { // return an Int value here } }
查询和设置属性
就像实例属性一样,类型属性可以通过“.”语法进行查询和设置,只是作用于类型本身,而不是指向实例。
struct StudMarks { static let markCount = 97 static var totalCount = 0 var InternalMarks: Int = 0 { didSet { if InternalMarks > StudMarks.markCount { InternalMarks = StudMarks.markCount } if InternalMarks > StudMarks.totalCount { StudMarks.totalCount = InternalMarks } } } } var stud1Mark1 = StudMarks() var stud1Mark2 = StudMarks() stud1Mark1.InternalMarks = 98 print(stud1Mark1.InternalMarks) stud1Mark2.InternalMarks = 87 print(stud1Mark2.InternalMarks)
当我们使用游乐场运行上述程序时,会得到以下结果:
97 87
Swift - 方法
在 Swift 4 语言中,与特定类型关联的函数称为方法。在 Objective C 中,类用于定义方法,而 Swift 4 语言允许用户为类、结构体和枚举灵活地定义方法。
实例方法
在 Swift 4 语言中,可以通过实例方法访问类、结构体和枚举的实例。
实例方法提供功能
- 访问和修改实例属性
- 与实例需求相关的功能
实例方法可以写在 {} 花括号内。它隐式地访问类型实例的方法和属性。当调用类型的特定实例时,它将访问该特定实例。
语法
func funcname(Parameters) -> returntype { Statement1 Statement2 --- Statement N return parameters }
示例
class calculations { let a: Int let b: Int let res: Int init(a: Int, b: Int) { self.a = a self.b = b res = a + b } func tot(c: Int) -> Int { return res - c } func result() { print("Result is: \(tot(c: 20))") print("Result is: \(tot(c: 50))") } } let pri = calculations(a: 600, b: 300) pri.result()
当我们使用游乐场运行上述程序时,会得到以下结果:
Result is: 880 Result is: 850
类计算定义了两个实例方法:
- 定义 init() 用于将两个数字 a 和 b 相加并将结果存储在结果 'res' 中
- tot() 用于从传递的 'c' 值中减去 'res'
最后,调用带有 a 和 b 值的计算方法以打印结果。实例方法通过“.”点语法访问。
局部参数名和外部参数名
Swift 4 函数描述了其变量的局部和全局声明。类似地,Swift 4 方法的命名约定也类似于 Objective C。但是,函数和方法的局部参数名和全局参数名声明的特性不同。Swift 4 中的第一个参数由介词名称(如“with”、“for”和“by”)引用,以便于访问命名约定。
Swift 4 通过将第一个参数名声明为局部参数名,并将其余参数名声明为全局参数名,从而在方法中提供了灵活性。这里,Swift 4 方法将 'no1' 声明为局部参数名。'no2' 用于全局声明,并在整个程序中访问。
class division { var count: Int = 0 func incrementBy(no1: Int, no2: Int) { count = no1 / no2 print(count) } } let counter = division() counter.incrementBy(no1: 1800, no2: 3) counter.incrementBy(no1: 1600, no2: 5) counter.incrementBy(no1: 11000, no2: 3)
当我们使用游乐场运行上述程序时,会得到以下结果:
600 320 3666
带 # 和 _ 符号的外部参数名
即使 Swift 4 方法为局部声明提供了第一个参数名,用户也可以将参数名从局部声明修改为全局声明。这可以通过在第一个参数名前加“#”符号来完成。这样做,可以在整个模块中全局访问第一个参数。
当用户需要使用外部名称访问后续参数名时,可以使用“_”符号覆盖方法名。
class multiplication { var count: Int = 0 func incrementBy(no1: Int, no2: Int) { count = no1 * no2 print(count) } } let counter = multiplication() counter.incrementBy(no1: 800, no2: 3) counter.incrementBy(no1: 100, no2: 5) counter.incrementBy(no1: 15000, no2: 3)
当我们使用游乐场运行上述程序时,会得到以下结果:
2400 500 45000
方法中的 Self 属性
对于所有定义的类型实例,方法都有一个称为“self”的隐式属性。“Self”属性用于引用当前实例及其定义的方法。
class calculations { let a: Int let b: Int let res: Int init(a: Int, b: Int) { self.a = a self.b = b res = a + b print("Inside Self Block: \(res)") } func tot(c: Int) -> Int { return res - c } func result() { print("Result is: \(tot(c: 20))") print("Result is: \(tot(c: 50))") } } let pri = calculations(a: 600, b: 300) let sum = calculations(a: 1200, b: 300) pri.result() sum.result()
当我们使用游乐场运行上述程序时,会得到以下结果:
Inside Self Block: 900 Inside Self Block: 1500 Result is: 880 Result is: 850 Result is: 1480 Result is: 1450
从实例方法修改值类型
在 Swift 4 语言中,结构体和枚举属于值类型,其实例方法无法更改它们。但是,Swift 4 语言提供了通过“mutating”行为修改值类型的灵活性。“mutate”将在实例方法中进行任何更改,并在方法执行后返回到原始形式。此外,通过“self”属性为其隐式函数创建新实例,并在其执行后替换现有方法。
struct area { var length = 1 var breadth = 1 func area() -> Int { return length * breadth } mutating func scaleBy(res: Int) { length *= res breadth *= res print(length) print(breadth) } } var val = area(length: 3, breadth: 5) val.scaleBy(res: 3) val.scaleBy(res: 30) val.scaleBy(res: 300)
当我们使用游乐场运行上述程序时,会得到以下结果:
9 15 270 450 81000 135000
可变方法的 Self 属性
可变方法与“self”属性结合,将新实例分配给定义的方法。
struct area { var length = 1 var breadth = 1 func area() -> Int { return length * breadth } mutating func scaleBy(res: Int) { self.length *= res self.breadth *= res print(length) print(breadth) } } var val = area(length: 3, breadth: 5) val.scaleBy(res: 13)
当我们在 playground 中运行上述程序时,会得到以下结果:
39 65
类型方法
当调用方法的特定实例时,称为实例方法;当方法调用方法的特定类型时,称为“类型方法”。类的类型方法由“func”关键字定义,结构体和枚举的类型方法在“func”关键字之前使用“static”关键字定义。
类型方法通过“.”语法调用和访问,其中调用整个方法而不是调用特定实例。
class Math { class func abs(number: Int) -> Int { if number < 0 { return (-number) } else { return number } } } struct absno { static func abs(number: Int) -> Int { if number < 0 { return (-number) } else { return number } } } let no = Math.abs(number: -35) let num = absno.abs(number: -5) print(no) print(num)
当我们在 playground 中运行上述程序时,会得到以下结果:
35 5
Swift - 下标
在类、结构体和枚举中,访问集合、序列和列表的元素成员是通过下标实现的。这些下标用于在索引的帮助下存储和检索值。数组元素通过 someArray[index] 访问,字典实例中的后续成员元素可以通过 someDicitonary[key] 访问。
对于单个类型,下标的范围可以从单个到多个声明。我们可以使用适当的下标来重载传递给下标的索引值的类型。根据用户对输入数据类型声明的要求,下标的范围也从一维到多维。
下标声明语法及其用法
让我们回顾一下计算属性。下标也遵循与计算属性相同的语法。对于查询类型实例,下标写在方括号内,后面跟着实例名称。下标语法遵循与“实例方法”和“计算属性”语法相同的语法结构。“subscript”关键字用于定义下标,用户可以指定一个或多个参数及其返回类型。下标可以具有读写或只读属性,实例通过“getter”和“setter”属性存储和检索,就像计算属性一样。
语法
subscript(index: Int) −> Int { get { // used for subscript value declarations } set(newValue) { // definitions are written here } }
示例 1
struct subexample { let decrementer: Int subscript(index: Int) -> Int { return decrementer / index } } let division = subexample(decrementer: 100) print("The number is divisible by \(division[9]) times") print("The number is divisible by \(division[2]) times") print("The number is divisible by \(division[3]) times") print("The number is divisible by \(division[5]) times") print("The number is divisible by \(division[7]) times")
当我们使用游乐场运行上述程序时,会得到以下结果:
The number is divisible by 11 times The number is divisible by 50 times The number is divisible by 33 times The number is divisible by 20 times The number is divisible by 14 times
示例 2
class daysofaweek { private var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "saturday"] subscript(index: Int) -> String { get { return days[index] } set(newValue) { self.days[index] = newValue } } } var p = daysofaweek() print(p[0]) print(p[1]) print(p[2]) print(p[3])
当我们使用游乐场运行上述程序时,会得到以下结果:
Sunday Monday Tuesday Wednesday
下标中的选项
下标接受一个到多个输入参数,这些输入参数也属于任何数据类型。它们还可以使用变量和可变参数。下标不能提供默认参数值或使用任何输入输出参数。
定义多个下标称为“下标重载”,其中类或结构体可以根据需要提供多个下标定义。这些多个下标根据在下标括号内声明的值的类型推断。
struct Matrix { let rows: Int, columns: Int var print: [Double] init(rows: Int, columns: Int) { self.rows = rows self.columns = columns print = Array(count: rows * columns, repeatedValue: 0.0) } subscript(row: Int, column: Int) -> Double { get { return print[(row * columns) + column] } set { print[(row * columns) + column] = newValue } } } var mat = Matrix(rows: 3, columns: 3) mat[0,0] = 1.0 mat[0,1] = 2.0 mat[1,0] = 3.0 mat[1,1] = 5.0 print("\(mat[0,0])")
当我们使用游乐场运行上述程序时,会得到以下结果:
1.0
Swift 4 下标支持为适当的数据类型声明单个参数到多个参数。程序将“Matrix”结构声明为一个 2 * 2 维数组矩阵,以存储“Double”数据类型。Matrix 参数使用整数数据类型输入以声明行和列。
通过将行数和列数传递给初始化器,可以创建 Matrix 的新实例,如下所示。
var mat = Matrix(rows: 3, columns: 3)
可以通过将行值和列值输入到下标中(用逗号分隔)来定义 Matrix 值,如下所示。
mat[0,0] = 1.0 mat[0,1] = 2.0 mat[1,0] = 3.0 mat[1,1] = 5.0
Swift - 继承
能够采用多种形式的能力定义为继承。通常,一个类可以从另一个类继承方法、属性和功能。类可以进一步分类为子类和超类。
子类 - 当一个类从另一个类继承属性、方法和函数时,称为子类
超类 - 包含属性、方法和函数以供其他类从中继承的类称为超类
Swift 4 类包含超类,它调用并访问方法、属性、函数和覆盖方法。此外,属性观察器也用于添加属性和修改存储或计算属性方法。
基类
不从另一个类继承方法、属性或函数的类称为“基类”。
class StudDetails { var stname: String! var mark1: Int! var mark2: Int! var mark3: Int! init(stname: String, mark1: Int, mark2: Int, mark3: Int) { self.stname = stname self.mark1 = mark1 self.mark2 = mark2 self.mark3 = mark3 } } let stname = "Swift 4" let mark1 = 98 let mark2 = 89 let mark3 = 76 print(stname) print(mark1) print(mark2) print(mark3)
当我们使用游乐场运行上述程序时,会得到以下结果:
Swift 4 98 89 76
此处将类名 StudDetails 的类定义为基类,用于包含学生姓名和三个科目成绩(mark1、mark2 和 mark3)。“let”关键字用于初始化基类值,基类值在 playground 中通过“print”函数显示。
子类
基于现有类创建新类的行为定义为“子类”。子类继承其基类的属性、方法和函数。要定义子类,在基类名前使用“:”
class StudDetails { var mark1: Int; var mark2: Int; init(stm1:Int, results stm2:Int) { mark1 = stm1; mark2 = stm2; } func print() { print("Mark1:\(mark1), Mark2:\(mark2)") } } class display : StudDetails { init() { super.init(stm1: 93, results: 89) } } let marksobtained = display() marksobtained.print()
当我们使用游乐场运行上述程序时,会得到以下结果:
Mark1:93, Mark2:89
类“StudDetails”被定义为超类,其中声明了学生成绩,子类“display”用于从其超类继承成绩。子类定义学生成绩并调用 print() 方法显示学生成绩。
重写
访问超类的实例、类型方法、实例、类型属性和下标,子类提供了重写概念。“override”关键字用于重写超类中声明的方法。
访问超类的方法、属性和下标
“super”关键字用作前缀以访问超类中声明的方法、属性和下标
重写 | 访问方法、属性和下标 |
方法 | super.somemethod() |
属性 | super.someProperty() |
下标 | super[someIndex] |
方法重写
继承的实例和类型方法可以通过“override”关键字重写为我们在子类中定义的方法。这里在子类中重写了 print() 以访问超类 print() 中提到的类型属性。此外,还创建了 cricket() 超类的新实例“cricinstance”。
class cricket { func print() { print("Welcome to Swift 4 Super Class") } } class tennis: cricket { override func print() { print("Welcome to Swift 4 Sub Class") } } let cricinstance = cricket() cricinstance.print() let tennisinstance = tennis() tennisinstance.print()
当我们使用游乐场运行上述程序时,会得到以下结果:
Welcome to Swift Super Class Welcome to Swift Sub Class
属性重写
您可以重写继承的实例或类属性,以提供您自己的自定义 getter 和 setter,或添加属性观察器以使重写属性能够观察底层属性值何时更改。
重写属性 Getter 和 Setter
Swift 4 允许用户提供自定义 getter 和 setter 来重写继承的属性,无论它是存储属性还是计算属性。子类不知道继承的属性名称和类型。因此,用户必须在子类中指定在超类中指定的重写属性的名称和类型。
这可以通过两种方式完成:
当为重写属性定义 setter 时,用户也必须定义 getter。
当我们不想修改继承的属性 getter 时,我们可以简单地通过语法“super.someProperty”将继承的值传递给超类。
class Circle { var radius = 12.5 var area: String { return "of rectangle for \(radius) " } } class Rectangle: Circle { var print = 7 override var area: String { return super.area + " is now overridden as \(print)" } } let rect = Rectangle() rect.radius = 25.0 rect.print = 3 print("Radius \(rect.area)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Radius of rectangle for 25.0 is now overridden as 3
重写属性观察器
当需要为继承的属性添加新属性时,Swift 4 中引入了“属性重写”的概念。这会在继承的属性值更改时通知用户。但是,重写不适用于继承的常量存储属性和继承的只读计算属性。
class Circle { var radius = 12.5 var area: String { return "of rectangle for \(radius) " } } class Rectangle: Circle { var print = 7 override var area: String { return super.area + " is now overridden as \(print)" } } let rect = Rectangle() rect.radius = 25.0 rect.print = 3 print("Radius \(rect.area)") class Square: Rectangle { override var radius: Double { didSet { print = Int(radius/5.0)+1 } } } let sq = Square() sq.radius = 100.0 print("Radius \(sq.area)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Radius of rectangle for 25.0 is now overridden as 3 Radius of rectangle for 100.0 is now overridden as 21
最终属性以防止重写
当用户不需要其他人访问超类的方法、属性或下标时,Swift 4 引入了“final”属性以防止重写。一旦声明了“final”属性,下标将不允许重写超类的方法、属性及其下标。超类中没有提供“final”属性。当声明“final”属性时,用户被限制创建进一步的子类。
final class Circle { final var radius = 12.5 var area: String { return "of rectangle for \(radius) " } } class Rectangle: Circle { var print = 7 override var area: String { return super.area + " is now overridden as \(print)" } } let rect = Rectangle() rect.radius = 25.0 rect.print = 3 print("Radius \(rect.area)") class Square: Rectangle { override var radius: Double { didSet { print = Int(radius/5.0)+1 } } } let sq = Square() sq.radius = 100.0 print("Radius \(sq.area)")
当我们使用游乐场运行上述程序时,会得到以下结果:
<stdin>:14:18: error: var overrides a 'final' var override var area: String { ^ <stdin>:7:9: note: overridden declaration is here var area: String { ^ <stdin>:12:11: error: inheritance from a final class 'Circle' class Rectangle: Circle { ^ <stdin>:25:14: error: var overrides a 'final' var override var radius: Double { ^ <stdin>:6:14: note: overridden declaration is here final var radius = 12.5
由于超类被声明为“final”,其数据类型也被声明为“final”,因此程序不允许进一步创建子类,并且会抛出错误。
Swift - 初始化
类、结构体和枚举一旦在 Swift 4 中声明,就会初始化以准备类的实例。为存储属性初始化初始值,并且对于新实例,也会初始化值以继续执行。创建初始化函数的关键字由“init()”方法执行。Swift 4 初始化器与 Objective-C 不同,它不返回值。其功能是在其处理之前检查新创建实例的初始化。Swift 4 还为在实例被释放后执行内存管理操作提供了“反初始化”过程。
初始化器对存储属性的作用
存储属性必须在处理实例之前初始化其类和结构的实例。存储属性使用初始化器分配和初始化值,从而消除了调用属性观察器的需要。初始化器用于存储属性
创建初始值。
在属性定义内分配默认属性值。
要初始化特定数据类型的实例,使用 'init()'。在 init() 函数内部不传递任何参数。
语法
init() { //New Instance initialization goes here }
示例
struct rectangle { var length: Double var breadth: Double init() { length = 6 breadth = 12 } } var area = rectangle() print("area of rectangle is \(area.length*area.breadth)")
当我们使用游乐场运行上述程序时,会得到以下结果:
area of rectangle is 72.0
这里,结构 'rectangle' 初始化为成员 length 和 breadth 作为 'Double' 数据类型。Init() 方法用于初始化新创建的成员 length 和 double 的值。通过调用 rectangle 函数计算并返回矩形的面积。
默认设置属性值
Swift 4 语言提供 Init() 函数来初始化存储属性值。此外,用户还可以选择在声明类或结构成员时默认初始化属性值。当属性在整个程序中仅取相同的值时,我们可以在声明部分声明它,而不是在 init() 中初始化它。默认设置属性值使用户能够在为类或结构定义继承时使用。
struct rectangle { var length = 6 var breadth = 12 } var area = rectangle() print("area of rectangle is \(area.length*area.breadth)")
当我们使用游乐场运行上述程序时,会得到以下结果:
area of rectangle is 72
这里,而不是在 init() 中声明 length 和 breadth,而是在声明中初始化值。
参数初始化
在 Swift 4 语言中,用户可以使用 init() 在初始化器的定义中初始化参数。
struct Rectangle { var length: Double var breadth: Double var area: Double init(fromLength length: Double, fromBreadth breadth: Double) { self.length = length self.breadth = breadth area = length * breadth } init(fromLeng leng: Double, fromBread bread: Double) { self.length = leng self.breadth = bread area = leng * bread } } let ar = Rectangle(fromLength: 6, fromBreadth: 12) print("area is: \(ar.area)") let are = Rectangle(fromLeng: 36, fromBread: 12) print("area is: \(are.area)")
当我们使用游乐场运行上述程序时,会得到以下结果:
area is: 72.0 area is: 432.0
局部和外部参数
初始化参数与函数和方法参数类似,都具有局部和全局参数名称。局部参数声明用于在初始化体内部访问,外部参数声明用于调用初始化器。Swift 4 初始化器与函数和方法初始化器不同,它们不识别哪个初始化器用于调用哪些函数。
为了克服这个问题,Swift 4 为 init() 中的每个参数都引入了自动外部名称。此自动外部名称等效于每个初始化参数之前编写的局部名称。
struct Days { let sunday, monday, tuesday: Int init(sunday: Int, monday: Int, tuesday: Int) { self.sunday = sunday self.monday = monday self.tuesday = tuesday } init(daysofaweek: Int) { sunday = daysofaweek monday = daysofaweek tuesday = daysofaweek } } let week = Days(sunday: 1, monday: 2, tuesday: 3) print("Days of a Week is: \(week.sunday)") print("Days of a Week is: \(week.monday)") print("Days of a Week is: \(week.tuesday)") let weekdays = Days(daysofaweek: 4) print("Days of a Week is: \(weekdays.sunday)") print("Days of a Week is: \(weekdays.monday)") print("Days of a Week is: \(weekdays.tuesday)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Days of a Week is: 1 Days of a Week is: 2 Days of a Week is: 3 Days of a Week is: 4 Days of a Week is: 4 Days of a Week is: 4
没有外部名称的参数
当初始化器不需要外部名称时,使用下划线 '_' 来覆盖默认行为。
struct Rectangle { var length: Double init(frombreadth breadth: Double) { length = breadth * 10 } init(frombre bre: Double) { length = bre * 30 } init(_ area: Double) { length = area } } let rectarea = Rectangle(180.0) print("area is: \(rectarea.length)") let rearea = Rectangle(370.0) print("area is: \(rearea.length)") let recarea = Rectangle(110.0) print("area is: \(recarea.length)")
当我们使用游乐场运行上述程序时,会得到以下结果:
area is: 180.0 area is: 370.0 area is: 110.0
可选属性类型
当存储属性在某些实例中不返回值时,该属性将声明为“可选”类型,表示该特定类型没有返回值。当存储属性声明为“可选”时,它会在初始化期间自动将值初始化为“nil”。
struct Rectangle { var length: Double? init(frombreadth breadth: Double) { length = breadth * 10 } init(frombre bre: Double) { length = bre * 30 } init(_ area: Double) { length = area } } let rectarea = Rectangle(180.0) print("area is: \(rectarea.length)") let rearea = Rectangle(370.0) print("area is: \(rearea.length)") let recarea = Rectangle(110.0) print("area is: \(recarea.length)")
当我们使用游乐场运行上述程序时,会得到以下结果:
area is: Optional(180.0) area is: Optional(370.0) area is: Optional(110.0)
在初始化期间修改常量属性
初始化还允许用户修改常量属性的值。在初始化期间,类属性允许其类实例被超类修改,而不是被子类修改。例如,在之前的程序中,'length' 在主类中声明为'变量'。下面的程序变量'length'被修改为'常量'变量。
struct Rectangle { let length: Double? init(frombreadth breadth: Double) { length = breadth * 10 } init(frombre bre: Double) { length = bre * 30 } init(_ area: Double) { length = area } } let rectarea = Rectangle(180.0) print("area is: \(rectarea.length)") let rearea = Rectangle(370.0) print("area is: \(rearea.length)") let recarea = Rectangle(110.0) print("area is: \(recarea.length)")
当我们使用游乐场运行上述程序时,会得到以下结果:
area is: Optional(180.0) area is: Optional(370.0) area is: Optional(110.0)
默认初始化器
默认初始化器为其所有声明的基本类或结构的属性提供具有默认值的新实例。
class defaultexample { var studname: String? var stmark = 98 var pass = true } var result = defaultexample() print("result is: \(result.studname)") print("result is: \(result.stmark)") print("result is: \(result.pass)")
当我们使用游乐场运行上面的程序时,我们得到以下结果。−
result is: nil result is: 98 result is: true
以上程序定义的类名为'defaultexample'。三个成员函数默认初始化为'studname?'以存储'nil'值,'stmark'为98,'pass'为布尔值'true'。同样,类中的成员值可以在处理类成员类型之前作为默认值初始化。
结构类型的逐一成员初始化器
当用户未提供自定义初始化器时,Swift 4 中的结构类型将自动接收“逐一成员初始化器”。其主要功能是使用默认的逐一成员初始化器初始化新的结构实例,然后将新实例属性按名称传递给逐一成员初始化器。
struct Rectangle { var length = 100.0, breadth = 200.0 } let area = Rectangle(length: 24.0, breadth: 32.0) print("Area of rectangle is: \(area.length)") print("Area of rectangle is: \(area.breadth)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Area of rectangle is: 24.0 Area of rectangle is: 32.0
在初始化期间,结构默认初始化其成员函数,其中“length”为“100.0”,“breadth”为“200.0”。但这些值在处理变量 length 和 breadth 为 24.0 和 32.0 时被覆盖。
值类型的初始化器委托
初始化器委托定义为从其他初始化器调用初始化器。其主要功能是作为可重用性,避免在多个初始化器之间重复代码。
struct Stmark { var mark1 = 0.0, mark2 = 0.0 } struct stdb { var m1 = 0.0, m2 = 0.0 } struct block { var average = stdb() var result = Stmark() init() {} init(average: stdb, result: Stmark) { self.average = average self.result = result } init(avg: stdb, result: Stmark) { let tot = avg.m1 - (result.mark1 / 2) let tot1 = avg.m2 - (result.mark2 / 2) self.init(average: stdb(m1: tot, m2: tot1), result: result) } } let set1 = block() print("student result is: \(set1.average.m1, set1.average.m2) \(set1.result.mark1, set1.result.mark2)") let set2 = block(average: stdb(m1: 2.0, m2: 2.0), result: Stmark(mark1: 5.0, mark2: 5.0)) print("student result is: \(set2.average.m1, set2.average.m2) \(set2.result.mark1, set2.result.mark2)") let set3 = block(avg: stdb(m1: 4.0, m2: 4.0), result: Stmark(mark1: 3.0, mark2: 3.0)) print("student result is: \(set3.average.m1, set3.average.m2) \(set3.result.mark1, set3.result.mark2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
(0.0,0.0) (0.0,0.0) (2.0,2.0) 5.0,5.0) (2.5,2.5) (3.0,3.0)
初始化器委托规则
值类型 | 类类型 |
---|---|
值类型(如结构和枚举)不支持继承。引用其他初始化器是通过 self.init 完成的 | 支持继承。检查所有存储属性值是否已初始化 |
类继承和初始化
类类型有两种类型的初始化器来检查定义的存储属性是否接收初始值,即指定初始化器和便利初始化器。
指定初始化器和便利初始化器
指定初始化器 | 便利初始化器 |
---|---|
被视为类的主要初始化器 | 被视为类的支持初始化器 |
所有类属性都已初始化,并为进一步初始化调用了相应的超类初始化器 | 便利初始化器调用指定初始化器以针对特定用例或输入值类型创建类实例 |
每个类至少定义一个指定初始化器。 | 当类不需要初始化器时,无需强制定义便利初始化器。 |
Init(parameters) { statements } | convenience init(parameters) { statements } |
指定初始化器程序
class mainClass { var no1 : Int // local storage init(no1 : Int) { self.no1 = no1 // initialization } } class subClass : mainClass { var no2 : Int // new subclass storage init(no1 : Int, no2 : Int) { self.no2 = no2 // initialization super.init(no1:no1) // redirect to superclass } } let res = mainClass(no1: 10) let print = subClass(no1: 10, no2: 20) print("res is: \(res.no1)") print("res is: \(print.no1)") print("res is: \(print.no2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
res is: 10 res is: 10 res is: 20
便利初始化器程序
class mainClass { var no1 : Int // local storage init(no1 : Int) { self.no1 = no1 // initialization } } class subClass : mainClass { var no2 : Int init(no1 : Int, no2 : Int) { self.no2 = no2 super.init(no1:no1) } // Requires only one parameter for convenient method override convenience init(no1: Int) { self.init(no1:no1, no2:0) } } let res = mainClass(no1: 20) let print = subClass(no1: 30, no2: 50) print("res is: \(res.no1)") print("res is: \(print.no1)") print("res is: \(print.no2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
res is: 20 res is: 30 res is: 50
初始化器继承和覆盖
Swift 4 默认不允许其子类继承其超类初始化器以用于其成员类型。继承仅在某种程度上适用于超类初始化器,这将在自动初始化器继承中讨论。
当用户需要在超类中定义初始化器时,必须由用户将带有初始化器的子类定义为自定义实现。当子类必须对超类进行覆盖时,必须声明“override”关键字。
class sides { var corners = 4 var description: String { return "\(corners) sides" } } let rectangle = sides() print("Rectangle: \(rectangle.description)") class pentagon: sides { override init() { super.init() corners = 5 } } let bicycle = pentagon() print("Pentagon: \(bicycle.description)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Rectangle: 4 sides Pentagon: 5 sides
指定和便利初始化器的实际应用
class Planet { var name: String init(name: String) { self.name = name } convenience init() { self.init(name: "[No Planets]") } } let plName = Planet(name: "Mercury") print("Planet name is: \(plName.name)") let noplName = Planet() print("No Planets like that: \(noplName.name)") class planets: Planet { var count: Int init(name: String, count: Int) { self.count = count super.init(name: name) } override convenience init(name: String) { self.init(name: name, count: 1) } }
当我们使用游乐场运行上述程序时,会得到以下结果:
Planet name is: Mercury No Planets like that: [No Planets]
可失败初始化器
在定义类、结构或枚举值时,必须通知用户是否存在任何初始化器失败。由于以下原因,变量的初始化有时会失败:−
- 无效的参数值。
- 缺少所需的外部源。
- 阻止初始化成功的条件。
为了捕获初始化方法抛出的异常,Swift 4 生成一个灵活的初始化器,称为“可失败初始化器”,以通知用户在初始化结构、类或枚举成员时是否有任何内容未被注意到。捕获可失败初始化器的关键字是“init?”。此外,可失败和不可失败初始化器不能使用相同的参数类型和名称定义。
struct studrecord { let stname: String init?(stname: String) { if stname.isEmpty {return nil } self.stname = stname } } let stmark = studrecord(stname: "Swing") if let name = stmark { print("Student name is specified") } let blankname = studrecord(stname: "") if blankname == nil { print("Student name is left blank") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Student name is specified Student name is left blank
枚举的可失败初始化器
Swift 4 语言提供了对枚举使用可失败初始化器的灵活性,以便在枚举成员未初始化值时通知用户。
enum functions { case a, b, c, d init?(funct: String) { switch funct { case "one": self = .a case "two": self = .b case "three": self = .c case "four": self = .d default: return nil } } } let result = functions(funct: "two") if result != nil { print("With In Block Two") } let badresult = functions(funct: "five") if badresult == nil { print("Block Does Not Exist") }
当我们使用游乐场运行上述程序时,会得到以下结果:
With In Block Two Block Does Not Exist
类的可失败初始化器
当使用枚举和结构声明可失败初始化器时,它会在其实现中的任何情况下发出初始化失败警报。但是,类中的可失败初始化器仅在将存储属性设置为初始值后才会发出失败警报。
class studrecord { let studname: String! init?(studname: String) { self.studname = studname if studname.isEmpty { return nil } } } if let stname = studrecord(studname: "Failable Initializers") { print("Module is \(stname.studname)") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Module is Optional("Failable Initializers")
覆盖可失败初始化器
就像初始化器一样,用户还可以在子类中覆盖超类的可失败初始化器。超类的可失败初始化器也可以在子类中使用不可失败初始化器覆盖。
当使用不可失败的子类初始化器覆盖可失败的超类初始化器时,子类初始化器不能委托给超类初始化器。
不可失败初始化器永远不能委托给可失败初始化器。
下面给出的程序描述了可失败和不可失败初始化器。
class Planet { var name: String init(name: String) { self.name = name } convenience init() { self.init(name: "[No Planets]") } } let plName = Planet(name: "Mercury") print("Planet name is: \(plName.name)") let noplName = Planet() print("No Planets like that: \(noplName.name)") class planets: Planet { var count: Int init(name: String, count: Int) { self.count = count super.init(name: name) } override convenience init(name: String) { self.init(name: name, count: 1) } }
当我们使用游乐场运行上述程序时,会得到以下结果:
Planet name is: Mercury No Planets like that: [No Planets]
init! 可失败初始化器
Swift 4 提供“init?”来定义可选实例可失败初始化器。要定义特定类型的隐式展开可选实例,“init!”被指定。
struct studrecord { let stname: String init!(stname: String) { if stname.isEmpty {return nil } self.stname = stname } } let stmark = studrecord(stname: "Swing") if let name = stmark { print("Student name is specified") } let blankname = studrecord(stname: "") if blankname == nil { print("Student name is left blank") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Student name is specified Student name is left blank
必需初始化器
要声明初始化器的每个子类,“required”关键字需要在 init() 函数之前定义。
class classA { required init() { var a = 10 print(a) } } class classB: classA { required init() { var b = 30 print(b) } } let res = classA() let print = classB()
当我们使用游乐场运行上述程序时,会得到以下结果:
10 30 10
Swift - 析构
在类实例需要被释放之前,必须调用“析构器”来释放内存空间。关键字“deinit”用于释放系统资源占用的内存空间。析构仅在类类型上可用。
释放内存空间的析构
Swift 4 在不再需要实例时自动释放实例以释放资源。Swift 4 通过自动引用计数 (ARC) 处理实例的内存管理,如自动引用计数中所述。通常,当您的实例被释放时,您不需要执行手动清理。但是,当您使用自己的资源时,您可能需要自己执行一些额外的清理。例如,如果您创建一个自定义类来打开文件并向其中写入一些数据,您可能需要在类实例被释放之前关闭该文件。
var counter = 0; // for reference counting class baseclass { init() { counter++; } deinit { counter--; } } var print: baseclass? = baseclass() print(counter) print = nil print(counter)
当我们使用游乐场运行上述程序时,会得到以下结果:
1 0
当省略 print = nil 语句时,计数器的值保持不变,因为它没有被析构。
var counter = 0; // for reference counting class baseclass { init() { counter++; } deinit { counter--; } } var print: baseclass? = baseclass() print(counter) print(counter)
当我们使用游乐场运行上述程序时,会得到以下结果:
1 1
Swift - ARC 概述
内存管理功能及其用法在 Swift 4 语言中通过自动引用计数 (ARC) 处理。ARC 用于初始化和释放系统资源,从而在不再需要实例时释放类实例使用的内存空间。ARC 跟踪代码实例之间关系的信息,以有效地管理内存资源。
ARC 的功能
每次通过 init() 创建新的类实例时,ARC 都会分配一块内存来存储信息。
有关实例类型及其值的信息存储在内存中。
当不再需要类实例时,它会通过 deinit() 自动释放内存空间,以便进一步存储和检索类实例。
ARC 跟踪当前引用的类实例属性、常量和变量,以便仅对未使用的实例应用 deinit()。
ARC 对那些类实例属性、常量和变量保持“强引用”,以在类实例当前正在使用时限制释放。
ARC 程序
class StudDetails { var stname: String! var mark: Int! init(stname: String, mark: Int) { self.stname = stname self.mark = mark } deinit { print("Deinitialized \(self.stname)") print("Deinitialized \(self.mark)") } } let stname = "Swift 4" let mark = 98 print(stname) print(mark)
当我们使用游乐场运行上述程序时,会得到以下结果:
Swift 4 98
ARC 强引用循环类实例
class studmarks { let name: String var stud: student? init (name: String) { print("Initializing: \(name)") self.name = name } deinit { print("Deallocating: \(self.name)") } } class student { let name: String var strname: studmarks? init (name: String) { print("Initializing: \(name)") self.name = name } deinit { print("Deallocating: \(self.name)") } } var shiba: studmarks? var mari: student? shiba = studmarks(name: "Swift 4") mari = student(name: "ARC") shiba!.stud = mari mari!.strname = shiba
当我们使用游乐场运行上述程序时,会得到以下结果:
Initializing: Swift 4 Initializing: ARC
ARC 弱引用和无主引用
类类型属性有两种方法可以解决强引用循环:−
- 弱引用
- 无主引用
这些引用用于使一个实例能够在引用循环中引用其他实例。然后,实例可以引用每个实例,而不必关心强引用循环。当用户知道某个实例可能返回“nil”值时,我们可以使用弱引用指向它。当实例要返回某些内容而不是 nil 时,则使用无主引用声明它。
弱引用程序
class module { let name: String init(name: String) { self.name = name } var sub: submodule? deinit { print("\(name) Is The Main Module") } } class submodule { let number: Int init(number: Int) { self.number = number } weak var topic: module? deinit { print("Sub Module with its topic number is \(number)") } } var toc: module? var list: submodule? toc = module(name: "ARC") list = submodule(number: 4) toc!.sub = list list!.topic = toc toc = nil list = nil
当我们使用游乐场运行上述程序时,会得到以下结果:
ARC Is The Main Module Sub Module with its topic number is 4
无主引用程序
class student { let name: String var section: marks? init(name: String) { self.name = name } deinit { print("\(name)") } } class marks { let marks: Int unowned let stname: student init(marks: Int, stname: student) { self.marks = marks self.stname = stname } deinit { print("Marks Obtained by the student is \(marks)") } } var module: student? module = student(name: "ARC") module!.section = marks(marks: 98, stname: module!) module = nil
当我们使用游乐场运行上述程序时,会得到以下结果:
ARC Marks Obtained by the student is 98
闭包的强引用循环
当我们将闭包赋值给类的实例属性,并且闭包体捕获了特定的实例时,可能会发生强引用循环。对闭包的强引用由 'self.someProperty' 或 'self.someMethod()' 定义。强引用循环被用作闭包的引用类型。
class HTMLElement { let samplename: String let text: String? lazy var asHTML: () -> String = { if let text = self.text { return "<\(self.samplename)>\(text)</\(self.samplename)>" } else { return "<\(self.samplename) />" } } init(samplename: String, text: String? = nil) { self.samplename = samplename self.text = text } deinit { print("\(samplename) is being deinitialized") } } var paragraph: HTMLElement? = HTMLElement(samplename: "p", text: "Welcome to Closure SRC") print(paragraph!.asHTML())
当我们使用游乐场运行上述程序时,会得到以下结果:
<p>Welcome to Closure SRC</p>
弱引用和无主引用
当闭包和实例相互引用时,用户可以在闭包中将捕获定义为无主引用。然后,它将不允许用户同时释放实例。当实例有时返回 'nil' 值时,使用弱实例定义闭包。
class HTMLElement { let module: String let text: String? lazy var asHTML: () -> String = { [unowned self] in if let text = self.text { return "<\(self.module)>\(text)</\(self.module)>" } else { return "<\(self.module) />" } } init(module: String, text: String? = nil) { self.module = module self.text = text } deinit { print("\(module) the deinit()") } } var paragraph: HTMLElement? = HTMLElement(module: "Inside", text: "ARC Weak References") print(paragraph!.asHTML()) paragraph = nil
当我们使用游乐场运行上述程序时,会得到以下结果:
<Inside>ARC Weak References</Inside> Inside the deinit()
Swift - 可选链
查询、调用可选值可能为 'nil' 的属性、下标和方法的过程称为可选链。可选链返回两个值:
如果可选值包含 'value',则调用其相关的属性、方法和下标将返回相应的值。
如果可选值包含 'nil' 值,则其所有相关的属性、方法和下标都将返回 nil。
由于多个对方法、属性和下标的查询被组合在一起,因此一个链的失败将影响整个链,并导致 'nil' 值。
可选链作为强制展开的替代方案
当可选值返回某些值时,在可选值后使用 '?' 指定可选链来调用属性、方法或下标。
可选链 '?' | 访问方法、属性和下标可选链 '!' 用于强制展开 |
? 放在可选值后面以调用属性、方法或下标 | ! 放在可选值后面以调用属性、方法或下标来强制展开值 |
当可选值为 'nil' 时,优雅地失败。 | 当可选值为 'nil' 时,强制展开会触发运行时错误。 |
使用 '!' 的可选链程序
class ElectionPoll { var candidate: Pollbooth? } lass Pollbooth { var name = "MP" } let cand = ElectionPoll() let candname = cand.candidate!.name
当我们使用游乐场运行上述程序时,会得到以下结果:
fatal error: unexpectedly found nil while unwrapping an Optional value 0 Swift 4 0x0000000103410b68 llvm::sys::PrintStackTrace(__sFILE*) + 40 1 Swift 4 0x0000000103411054 SignalHandler(int) + 452 2 libsystem_platform.dylib 0x00007fff9176af1a _sigtramp + 26 3 libsystem_platform.dylib 0x000000000000000b _sigtramp + 1854492939 4 libsystem_platform.dylib 0x00000001074a0214 _sigtramp + 1976783636 5 Swift 4 0x0000000102a85c39 llvm::JIT::runFunction(llvm::Function*, std::__1::vector > const&) + 329 6 Swift 4 0x0000000102d320b3 llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*, std::__1::vector<std::__1::basic_string, std::__1::allocator >, std::__1::allocator<std::__1::basic_string, std::__1::allocator > > > const&, char const* const*) + 1523 7 Swift 4 0x000000010296e6ba Swift 4::RunImmediately(Swift 4::CompilerInstance&, std::__1::vector<std::__1::basic_string, std::__1::allocator >, std::__1::allocator<std::__1::basic_string, std::__1::allocator > > > const&, Swift 4::IRGenOptions&, Swift 4::SILOptions const&) + 1066 8 Swift 4 0x000000010275764b frontend_main(llvm::ArrayRef, char const*, void*) + 5275 9 Swift 4 0x0000000102754a6d main + 1677 10 libdyld.dylib 0x00007fff8bb9e5c9 start + 1 11 libdyld.dylib 0x000000000000000c start + 1950751300 Stack dump: 0. Program arguments: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/ usr/bin/Swift 4 -frontend -interpret - -target x86_64-apple-darwin14.0.0 - target-cpu core2 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/ SDKs/MacOSX10.10.sdk -module-name main /bin/sh: line 47: 15672 Done cat <<'SWIFT 4' import Foundation </std::__1::basic_string</std::__1::basic_string</std::__1::basic_string</std:: __1::basic_string
上面的程序声明 'election poll' 作为类名,并包含 'candidate' 作为成员函数。子类声明为 'poll booth','name' 作为其成员函数,初始化为 'MP'。对父类的调用通过创建带可选 '!' 的实例 'cand' 来初始化。由于在基类中没有声明值,因此存储 'nil' 值,从而通过强制展开过程返回致命错误。
使用 '?' 的可选链程序
class ElectionPoll { var candidate: Pollbooth? } class Pollbooth { var name = "MP" } let cand = ElectionPoll() if let candname = cand.candidate?.name { print("Candidate name is \(candname)") } else { print("Candidate name cannot be retreived") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Candidate name cannot be retreived
上面的程序声明 'election poll' 作为类名,并包含 'candidate' 作为成员函数。子类声明为 'poll booth','name' 作为其成员函数,初始化为 'MP'。对父类的调用通过创建带可选 '?' 的实例 'cand' 来初始化。由于在基类中没有声明值,因此存储 'nil' 值,并由 else 处理程序块在控制台中打印。
为可选链和属性访问定义模型类
Swift 4 语言还提供了可选链的概念,以声明多个子类作为模型类。此概念对于定义复杂的模型以及访问属性、方法和下标子属性非常有用。
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var street: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let rectname = rectangle() if let rectarea = rectname.print?.cprint { print("Area of rectangle is \(rectarea)") } else { print("Rectangle Area is not specified") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Rectangle Area is not specified
通过可选链调用方法
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("Area of Circle is: \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if circname.print?.circleprint() != nil { print("Area of circle is specified)") } else { print("Area of circle is not specified") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Area of circle is not specified
通过创建名为 'circname' 的实例来调用在 circle() 子类中声明的函数 circleprint()。如果函数包含某些值,则该函数将返回值,否则它将通过检查语句 'if circname.print?.circleprint() != nil' 返回一些用户定义的打印消息。
通过可选链访问下标
可选链用于设置和检索下标值,以验证对该下标的调用是否返回值。在方括号之前放置 '?' 以访问特定下标上的可选值。
程序 1
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if let radiusName = circname.print?[0].radiusname { print("The first room name is \(radiusName).") } else { print("Radius is not specified.") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Radius is not specified.
在上面的程序中,没有指定成员函数 'radiusName' 的实例值。因此,对函数的程序调用将仅返回 else 部分,而要返回值,我们必须为特定成员函数定义值。
程序 2
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() circname.print?[0] = radius(radiusname: "Diameter") let printing = circle() printing.area.append(radius(radiusname: "Units")) printing.area.append(radius(radiusname: "Meter")) circname.print = printing if let radiusName = circname.print?[0].radiusname { print("Radius is measured in \(radiusName).") } else { print("Radius is not specified.") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Radius is measured in Units.
在上面的程序中,指定了成员函数 'radiusName' 的实例值。因此,对函数的程序调用现在将返回值。
访问可选类型下标
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() circname.print?[0] = radius(radiusname: "Diameter") let printing = circle() printing.area.append(radius(radiusname: "Units")) printing.area.append(radius(radiusname: "Meter")) circname.print = printing var area = ["Radius": [35, 45, 78, 101], "Circle": [90, 45, 56]] area["Radius"]?[1] = 78 area["Circle"]?[1]-- print(area["Radius"]?[0]) print(area["Radius"]?[1]) print(area["Radius"]?[2]) print(area["Radius"]?[3]) print(area["Circle"]?[0]) print(area["Circle"]?[1]) print(area["Circle"]?[2])
当我们使用游乐场运行上述程序时,会得到以下结果:
Optional(35) Optional(78) Optional(78) Optional(101) Optional(90) Optional(44) Optional(56)
可以通过引用其下标值来访问下标的可选值。它可以访问为 subscript[0]、subscript[1] 等。'radius' 的默认下标值首先赋值为 [35, 45, 78, 101],'Circle' 的默认下标值赋值为 [90, 45, 56]]。然后,下标值更改为 Radius[0] 为 78,Circle[1] 为 45。
链接多个级别的链
多个子类也可以通过可选链与其父类的方法、属性和下标链接。
可选的多个链可以链接:
如果检索类型不是可选的,则可选链将返回一个可选值。例如,如果通过可选链检索 String,它将返回 String? 值。
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if let radiusName = circname.print?[0].radiusname { print("The first room name is \(radiusName).") } else { print("Radius is not specified.") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Radius is not specified.
在上面的程序中,没有指定成员函数 'radiusName' 的实例值。因此,对函数的程序调用将仅返回 else 部分,而要返回值,我们必须为特定成员函数定义值。
如果检索类型已经是可选的,则可选链也将返回一个可选值。例如,如果通过可选链访问 String?,它将返回 String? 值。
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() circname.print?[0] = radius(radiusname: "Diameter") let printing = circle() printing.area.append(radius(radiusname: "Units")) printing.area.append(radius(radiusname: "Meter")) circname.print = printing if let radiusName = circname.print?[0].radiusname { print("Radius is measured in \(radiusName).") } else { print("Radius is not specified.") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Radius is measured in Units.
在上面的程序中,指定了成员函数 'radiusName' 的实例值。因此,对函数的程序调用现在将返回值。
对具有可选返回值的方法进行链式调用
可选链用于访问子类定义的方法。
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("Area of Circle is: \(cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if circname.print?.circleprint() != nil { print("Area of circle is specified)") } else { print("Area of circle is not specified") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Area of circle is not specified
Swift - 类型转换
为了验证实例的类型,Swift 4 语言中引入了“类型转换”。它用于检查实例类型是否属于特定的父类或子类,或者它是否在其自己的层次结构中定义。
Swift 4 类型转换提供了两个运算符:'is' 用于检查值的类型,'as' 用于将类型值转换为不同的类型。类型转换还检查实例类型是否遵循特定的协议一致性标准。
定义类层次结构
类型转换用于检查实例的类型,以确定它是否属于特定的类类型。此外,它检查类及其子类的层次结构,以检查和转换这些实例,使其成为相同的层次结构。
class Subjects { var physics: String init(physics: String) { self.physics = physics } } class Chemistry: Subjects { var equations: String init(physics: String, equations: String) { self.equations = equations super.init(physics: physics) } } class Maths: Subjects { var formulae: String init(physics: String, formulae: String) { self.formulae = formulae super.init(physics: physics) } } let sa = [ Chemistry(physics: "solid physics", equations: "Hertz"), Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")] let samplechem = Chemistry(physics: "solid physics", equations: "Hertz") print("Instance physics is: \(samplechem.physics)") print("Instance equation is: \(samplechem.equations)") let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz") print("Instance physics is: \(samplemaths.physics)") print("Instance formulae is: \(samplemaths.formulae)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Instance physics is: solid physics Instance equation is: Hertz Instance physics is: Fluid Dynamics Instance formulae is: Giga Hertz
类型检查
类型检查使用 'is' 运算符完成。'is' 类型检查运算符检查实例是否属于特定的子类类型,如果属于该实例则返回 'true',否则返回 'false'。
class Subjects { var physics: String init(physics: String) { self.physics = physics } } class Chemistry: Subjects { var equations: String init(physics: String, equations: String) { self.equations = equations super.init(physics: physics) } } class Maths: Subjects { var formulae: String init(physics: String, formulae: String) { self.formulae = formulae super.init(physics: physics) } } let sa = [ Chemistry(physics: "solid physics", equations: "Hertz"), Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"), Chemistry(physics: "Thermo physics", equations: "Decibels"), Maths(physics: "Astro Physics", formulae: "MegaHertz"), Maths(physics: "Differential Equations", formulae: "Cosine Series")] let samplechem = Chemistry(physics: "solid physics", equations: "Hertz") print("Instance physics is: \(samplechem.physics)") print("Instance equation is: \(samplechem.equations)") let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz") print("Instance physics is: \(samplemaths.physics)") print("Instance formulae is: \(samplemaths.formulae)") var chemCount = 0 var mathsCount = 0 for item in sa { if item is Chemistry { ++chemCount } else if item is Maths { ++mathsCount } } print("Subjects in chemistry contains \(chemCount) topics and maths contains \(mathsCount) topics")
当我们使用游乐场运行上述程序时,会得到以下结果:
Instance physics is: solid physics Instance equation is: Hertz Instance physics is: Fluid Dynamics Instance formulae is: Giga Hertz Subjects in chemistry contains 2 topics and maths contains 3 topics
向下转换
可以使用两个运算符 (as? 和 as!) 对子类类型进行向下转换。'as?' 在值返回 nil 时返回一个可选值。它用于检查向下转换是否成功。
'as!' 返回强制展开(如可选链中所述),当向下转换返回 nil 值时。它用于在向下转换失败时触发运行时错误。
class Subjects { var physics: String init(physics: String) { self.physics = physics } } class Chemistry: Subjects { var equations: String init(physics: String, equations: String) { self.equations = equations super.init(physics: physics) } } class Maths: Subjects { var formulae: String init(physics: String, formulae: String) { self.formulae = formulae super.init(physics: physics) } } let sa = [ Chemistry(physics: "solid physics", equations: "Hertz"), Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"), Chemistry(physics: "Thermo physics", equations: "Decibels"), Maths(physics: "Astro Physics", formulae: "MegaHertz"), Maths(physics: "Differential Equations", formulae: "Cosine Series")] let samplechem = Chemistry(physics: "solid physics", equations: "Hertz") print("Instance physics is: \(samplechem.physics)") print("Instance equation is: \(samplechem.equations)") let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz") print("Instance physics is: \(samplemaths.physics)") print("Instance formulae is: \(samplemaths.formulae)") var chemCount = 0 var mathsCount = 0 for item in sa { if let print = item as? Chemistry { print("Chemistry topics are: '\(print.physics)', \(print.equations)") } else if let example = item as? Maths { print("Maths topics are: '\(example.physics)', \(example.formulae)") } }
当我们使用游乐场运行上述程序时,会得到以下结果:
Instance physics is: solid physics Instance equation is: Hertz Instance physics is: Fluid Dynamics Instance formulae is: Giga Hertz Chemistry topics are: 'solid physics', Hertz Maths topics are: 'Fluid Dynamics', Giga Hertz Chemistry topics are: 'Thermo physics', Decibels Maths topics are: 'Astro Physics', MegaHertz Maths topics are: 'Differential Equations', Cosine Series
类型转换:Any 和 AnyObject
关键字 'Any' 用于表示属于任何类型的实例,包括函数类型。
class Subjects { var physics: String init(physics: String) { self.physics = physics } } class Chemistry: Subjects { var equations: String init(physics: String, equations: String) { self.equations = equations super.init(physics: physics) } } class Maths: Subjects { var formulae: String init(physics: String, formulae: String) { self.formulae = formulae super.init(physics: physics) } } let sa = [ Chemistry(physics: "solid physics", equations: "Hertz"), Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"), Chemistry(physics: "Thermo physics", equations: "Decibels"), Maths(physics: "Astro Physics", formulae: "MegaHertz"), Maths(physics: "Differential Equations", formulae: "Cosine Series")] let samplechem = Chemistry(physics: "solid physics", equations: "Hertz") print("Instance physics is: \(samplechem.physics)") print("Instance equation is: \(samplechem.equations)") let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz") print("Instance physics is: \(samplemaths.physics)") print("Instance formulae is: \(samplemaths.formulae)") var chemCount = 0 var mathsCount = 0 for item in sa { if let print = item as? Chemistry { print("Chemistry topics are: '\(print.physics)', \(print.equations)") } else if let example = item as? Maths { print("Maths topics are: '\(example.physics)', \(example.formulae)") } } var exampleany = [Any]() exampleany.append(12) exampleany.append(3.14159) exampleany.append("Example for Any") exampleany.append(Chemistry(physics: "solid physics", equations: "Hertz")) for print in exampleany { switch print { case let someInt as Int: print("Integer value is \(someInt)") case let someDouble as Double where someDouble > 0: print("Pi value is \(someDouble)") case let someString as String: print("\(someString)") case let phy as Chemistry: print("Topics '\(phy.physics)', \(phy.equations)") default: print("None") } }
当我们使用游乐场运行上述程序时,会得到以下结果:
Instance physics is: solid physics Instance equation is: Hertz Instance physics is: Fluid Dynamics Instance formulae is: Giga Hertz Chemistry topics are: 'solid physics', Hertz Maths topics are: 'Fluid Dynamics', Giga Hertz Chemistry topics are: 'Thermo physics', Decibels Maths topics are: 'Astro Physics', MegaHertz Maths topics are: 'Differential Equations', Cosine Series Integer value is 12 Pi value is 3.14159 Example for Any Topics 'solid physics', Hertz
AnyObject
为了表示任何类类型的实例,使用 'AnyObject' 关键字。
class Subjects { var physics: String init(physics: String) { self.physics = physics } } class Chemistry: Subjects { var equations: String init(physics: String, equations: String) { self.equations = equations super.init(physics: physics) } } class Maths: Subjects { var formulae: String init(physics: String, formulae: String) { self.formulae = formulae super.init(physics: physics) } } let saprint: [AnyObject] = [Chemistry(physics: "solid physics", equations: "Hertz"), Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"), Chemistry(physics: "Thermo physics", equations: "Decibels"), Maths(physics: "Astro Physics", formulae: "MegaHertz"), Maths(physics: "Differential Equations", formulae: "Cosine Series")] let samplechem = Chemistry(physics: "solid physics", equations: "Hertz") print("Instance physics is: \(samplechem.physics)") print("Instance equation is: \(samplechem.equations)") let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz") print("Instance physics is: \(samplemaths.physics)") print("Instance formulae is: \(samplemaths.formulae)") var chemCount = 0 var mathsCount = 0 for item in saprint { if let print = item as? Chemistry { print("Chemistry topics are: '\(print.physics)', \(print.equations)") } else if let example = item as? Maths { print("Maths topics are: '\(example.physics)', \(example.formulae)") } } var exampleany = [Any]() exampleany.append(12) exampleany.append(3.14159) exampleany.append("Example for Any") exampleany.append(Chemistry(physics: "solid physics", equations: "Hertz")) for print in exampleany { switch print { case let someInt as Int: print("Integer value is \(someInt)") case let someDouble as Double where someDouble > 0: print("Pi value is \(someDouble)") case let someString as String: print("\(someString)") case let phy as Chemistry: print("Topics '\(phy.physics)', \(phy.equations)") default: print("None") } }
当我们使用游乐场运行上述程序时,会得到以下结果:
Instance physics is: solid physics Instance equation is: Hertz Instance physics is: Fluid Dynamics Instance formulae is: Giga Hertz Chemistry topics are: 'solid physics', Hertz Maths topics are: 'Fluid Dynamics', Giga Hertz Chemistry topics are: 'Thermo physics', Decibels Maths topics are: 'Astro Physics', MegaHertz Maths topics are: 'Differential Equations', Cosine Series Integer value is 12 Pi value is 3.14159 Example for Any Topics 'solid physics', Hertz
Swift - 扩展
可以通过扩展来添加现有类、结构或枚举类型的功能。可以使用扩展添加类型功能,但无法使用扩展覆盖功能。
Swift 扩展功能:
- 添加计算属性和计算类型属性
- 定义实例方法和类型方法。
- 提供新的初始化器。
- 定义下标
- 定义和使用新的嵌套类型
- 使现有类型符合协议
扩展使用关键字 'extension' 声明。
语法
extension SomeType { // new functionality can be added here }
现有类型也可以通过扩展添加,使其成为协议标准,其语法类似于类或结构。
extension SomeType: SomeProtocol, AnotherProtocol { // protocol requirements is described here }
计算属性
计算“实例”和“类型”属性也可以通过扩展添加。
extension Int { var add: Int {return self + 100 } var sub: Int { return self - 10 } var mul: Int { return self * 10 } var div: Int { return self / 5 } } let addition = 3.add print("Addition is \(addition)") let subtraction = 120.sub print("Subtraction is \(subtraction)") let multiplication = 39.mul print("Multiplication is \(multiplication)") let division = 55.div print("Division is \(division)") let mix = 30.add + 34.sub print("Mixed Type is \(mix)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Addition is 103 Subtraction is 110 Multiplication is 390 Division is 11 Mixed Type is 154
初始化器
Swift 4 提供了通过扩展向现有类型添加新初始化器的灵活性。用户可以添加自己的自定义类型来扩展已定义的类型,并且还提供了其他初始化选项。扩展仅支持 init()。deinit() 不受扩展支持。
struct sum { var num1 = 100, num2 = 200 } struct diff { var no1 = 200, no2 = 100 } struct mult { var a = sum() var b = diff() } let calc = mult() print ("Inside mult block \(calc.a.num1, calc.a.num2)") print("Inside mult block \(calc.b.no1, calc.b.no2)") let memcalc = mult(a: sum(num1: 300, num2: 500),b: diff(no1: 300, no2: 100)) print("Inside mult block \(memcalc.a.num1, memcalc.a.num2)") print("Inside mult block \(memcalc.b.no1, memcalc.b.no2)") extension mult { init(x: sum, y: diff) { let X = x.num1 + x.num2 let Y = y.no1 + y.no2 } } let a = sum(num1: 100, num2: 200) print("Inside Sum Block:\( a.num1, a.num2)") let b = diff(no1: 200, no2: 100) print("Inside Diff Block: \(b.no1, b.no2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Inside mult block (100, 200) Inside mult block (200, 100) Inside mult block (300, 500) Inside mult block (300, 100) Inside Sum Block:(100, 200) Inside Diff Block: (200, 100)
方法
可以使用扩展进一步向子类添加新的实例方法和类型方法。
extension Int { func topics(summation: () -> ()) { for _ in 0..<self { summation() } } } 4.topics(summation: { print("Inside Extensions Block") }) 3.topics(summation: { print("Inside Type Casting Block") })
当我们使用游乐场运行上述程序时,会得到以下结果:
Inside Extensions Block Inside Extensions Block Inside Extensions Block Inside Extensions Block Inside Type Casting Block Inside Type Casting Block Inside Type Casting Block
topics() 函数采用类型为 '(summation: () → ())' 的参数,以指示该函数不接受任何参数,并且不会返回任何值。为了多次调用该函数,初始化了 for 块并初始化了对 topic() 方法的调用。
可变实例方法
当声明为扩展时,实例方法也可以被修改。
修改 self 或其属性的结构和枚举方法必须将实例方法标记为 mutating,就像来自原始实现的可变方法一样。
extension Double { mutating func square() { let pi = 3.1415 self = pi * self * self } } var Trial1 = 3.3 Trial1.square() print("Area of circle is: \(Trial1)") var Trial2 = 5.8 Trial2.square() print("Area of circle is: \(Trial2)") var Trial3 = 120.3 Trial3.square() print("Area of circle is: \(Trial3)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Area of circle is: 34.210935 Area of circle is: 105.68006 Area of circle is: 45464.070735
下标
向已声明的实例添加新的下标也可以通过扩展实现。
extension Int { subscript(var multtable: Int) -> Int { var no1 = 1 while multtable > 0 { no1 *= 10 --multtable } return (self / no1) % 10 } } print(12[0]) print(7869[1]) print(786543[2])
当我们使用游乐场运行上述程序时,会得到以下结果:
2 6 5
嵌套类型
类、结构和枚举实例的嵌套类型也可以通过扩展添加。
extension Int { enum calc { case add case sub case mult case div case anything } var print: calc { switch self { case 0: return .add case 1: return .sub case 2: return .mult case 3: return .div default: return .anything } } } func result(numb: [Int]) { for i in numb { switch i.print { case .add: print(" 10 ") case .sub: print(" 20 ") case .mult: print(" 30 ") case .div: print(" 40 ") default: print(" 50 ") } } } result(numb: [0, 1, 2, 3, 4, 7])
当我们使用游乐场运行上述程序时,会得到以下结果:
10 20 30 40 50 50
Swift - 协议
协议为方法、属性和其他需求功能提供蓝图。它只是描述为方法或属性的骨架,而不是实现。方法和属性的实现可以通过定义类、函数和枚举来进一步完成。协议的一致性定义为方法或属性满足协议的要求。
语法
协议也遵循与类、结构和枚举类似的语法:
protocol SomeProtocol { // protocol definition }
协议在类、结构或枚举类型名称之后声明。单协议和多协议声明也是可能的。如果定义了多个协议,则必须用逗号分隔。
struct SomeStructure: Protocol1, Protocol2 { // structure definition }
当必须为父类定义协议时,协议名称应在父类名称后面加上逗号。
class SomeClass: SomeSuperclass, Protocol1, Protocol2 { // class definition }
属性和方法要求
协议用于指定特定类类型的属性或实例属性。它只指定类型或实例属性本身,而不是指定它是存储属性还是计算属性。此外,它用于指定属性是“可获取的”还是“可设置的”。
属性要求由 'var' 关键字声明为属性变量。{get set} 用于在类型声明后声明可获取和可设置的属性。可获取在类型声明后的 {get} 属性中提及。
protocol classa { var marks: Int { get set } var result: Bool { get } func attendance() -> String func markssecured() -> String } protocol classb: classa { var present: Bool { get set } var subject: String { get set } var stname: String { get set } } class classc: classb { var marks = 96 let result = true var present = false var subject = "Swift 4 Protocols" var stname = "Protocols" func attendance() -> String { return "The \(stname) has secured 99% attendance" } func markssecured() -> String { return "\(stname) has scored \(marks)" } } let studdet = classc() studdet.stname = "Swift 4" studdet.marks = 98 studdet.markssecured() print(studdet.marks) print(studdet.result) print(studdet.present) print(studdet.subject) print(studdet.stname)
当我们使用游乐场运行上述程序时,会得到以下结果:
98 true false Swift 4 Protocols Swift 4
可变方法要求
protocol daysofaweek { mutating func print() } enum days: daysofaweek { case sun, mon, tue, wed, thurs, fri, sat mutating func print() { switch self { case sun: self = sun print("Sunday") case mon: self = mon print("Monday") case tue: self = tue print("Tuesday") case wed: self = wed print("Wednesday") case mon: self = thurs print("Thursday") case tue: self = fri print("Friday") case sat: self = sat print("Saturday") default: print("NO Such Day") } } } var res = days.wed res.print()
当我们使用游乐场运行上述程序时,会得到以下结果:
Wednesday
初始化器要求
Swing 允许用户初始化协议以遵循与普通初始化器类似的类型一致性。
语法
protocol SomeProtocol { init(someParameter: Int) }
例如
protocol tcpprotocol { init(aprot: Int) }
协议初始化器要求的类实现
指定或便利初始化器允许用户初始化一个协议,以通过保留的 'required' 关键字使其符合其标准。
class SomeClass: SomeProtocol { required init(someParameter: Int) { // initializer implementation statements } } protocol tcpprotocol { init(aprot: Int) } class tcpClass: tcpprotocol { required init(aprot: Int) { } }
通过 'required' 修饰符,在所有子类上都确保协议一致性,以进行显式或继承的实现。
当子类覆盖其超类初始化要求时,由“override”修饰符关键字指定。
protocol tcpprotocol { init(no1: Int) } class mainClass { var no1: Int // local storage init(no1: Int) { self.no1 = no1 // initialization } } class subClass: mainClass, tcpprotocol { var no2: Int init(no1: Int, no2 : Int) { self.no2 = no2 super.init(no1:no1) } // Requires only one parameter for convenient method required override convenience init(no1: Int) { self.init(no1:no1, no2:0) } } let res = mainClass(no1: 20) let print = subClass(no1: 30, no2: 50) print("res is: \(res.no1)") print("res is: \(print.no1)") print("res is: \(print.no2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
res is: 20 res is: 30 res is: 50
协议作为类型
协议不用于实现功能,而是用作函数、类、方法等的类型。
协议可以在以下方面用作类型:
函数、方法或初始化作为参数或返回类型
常量、变量或属性
数组、字典或其他容器中的项
protocol Generator { typealias members func next() -> members? } var items = [10,20,30].generate() while let x = items.next() { print(x) } for lists in map([1,2,3], {i in i*5}) { print(lists) } print([100,200,300]) print(map([1,2,3], {i in i*10}))
当我们使用游乐场运行上述程序时,会得到以下结果:
10 20 30 5 10 15 [100, 200, 300] [10, 20, 30]
使用扩展添加协议一致性
可以通过使用扩展采用现有的类型并使其符合新协议。可以使用扩展向现有类型添加新的属性、方法和下标。
protocol AgeClasificationProtocol { var age: Int { get } func agetype() -> String } class Person { let firstname: String let lastname: String var age: Int init(firstname: String, lastname: String) { self.firstname = firstname self.lastname = lastname self.age = 10 } } extension Person : AgeClasificationProtocol { func fullname() -> String { var c: String c = firstname + " " + lastname return c } func agetype() -> String { switch age { case 0...2: return "Baby" case 2...12: return "Child" case 13...19: return "Teenager" case let x where x > 65: return "Elderly" default: return "Normal" } } }
协议继承
Swift 4 允许协议从其定义的属性继承属性。这类似于类继承,但可以选择用逗号分隔多个继承的协议。
protocol classa { var no1: Int { get set } func calc(sum: Int) } protocol result { func print(target: classa) } class student2: result { func print(target: classa) { target.calc(sum: 1) } } class classb: result { func print(target: classa) { target.calc(sum: 5) } } class student: classa { var no1: Int = 10 func calc(sum: Int) { no1 -= sum print("Student attempted \(sum) times to pass") if no1 <= 0 { print("Student is absent for exam") } } } class Player { var stmark: result! init(stmark: result) { self.stmark = stmark } func print(target: classa) { stmark.print(target: target) } } var marks = Player(stmark: student2()) var marksec = student() marks.print(target: marksec) marks.print(target: marksec) marks.print(target: marksec) marks.stmark = classb() marks.print(target: marksec) marks.print(target: marksec) marks.print(target: marksec)
当我们使用游乐场运行上述程序时,会得到以下结果:
Student attempted 1 times to pass Student attempted 1 times to pass Student attempted 1 times to pass Student attempted 5 times to pass Student attempted 5 times to pass Student is absent for exam Student attempted 5 times to pass Student is absent for exam
仅限类协议
当定义协议并且用户希望使用类定义协议时,应首先定义类,然后定义协议的继承列表。
protocol tcpprotocol { init(no1: Int) } class mainClass { var no1: Int // local storage init(no1: Int) { self.no1 = no1 // initialization } } class subClass: mainClass, tcpprotocol { var no2: Int init(no1: Int, no2 : Int) { self.no2 = no2 super.init(no1:no1) } // Requires only one parameter for convenient method required override convenience init(no1: Int) { self.init(no1:no1, no2:0) } } let res = mainClass(no1: 20) let print = subClass(no1: 30, no2: 50) print("res is: \(res.no1)") print("res is: \(print.no1)") print("res is: \(print.no2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
res is: 20 res is: 30 res is: 50
协议组合
Swift 4 允许使用协议组合同时调用多个协议。
语法
protocol<SomeProtocol, AnotherProtocol>
示例
protocol stname { var name: String { get } } protocol stage { var age: Int { get } } struct Person: stname, stage { var name: String var age: Int } func print(celebrator: stname & stage) { print("\(celebrator.name) is \(celebrator.age) years old") } let studname = Person(name: "Priya", age: 21) print(studname) let stud = Person(name: "Rehan", age: 29) print(stud) let student = Person(name: "Roshan", age: 19) print(student)
当我们使用游乐场运行上述程序时,会得到以下结果:
Person(name: "Priya", age: 21) Person(name: "Rehan", age: 29) Person(name: "Roshan", age: 19)
检查协议一致性
协议一致性通过“is”和“as”运算符进行测试,类似于类型转换。
如果实例符合协议标准,“is”运算符返回 true,如果失败则返回 false。
as?版本的向下转换运算符返回协议类型的可选值,如果实例不符合该协议,则此值为 nil。
as版本的向下转换运算符强制向下转换为协议类型,如果向下转换不成功,则会触发运行时错误。
import Foundation @objc protocol rectangle { var area: Double { get } } @objc class Circle: rectangle { let pi = 3.1415927 var radius: Double var area: Double { return pi * radius * radius } init(radius: Double) { self.radius = radius } } @objc class result: rectangle { var area: Double init(area: Double) { self.area = area } } class sides { var rectsides: Int init(rectsides: Int) { self.rectsides = rectsides } } let objects: [AnyObject] = [Circle(radius: 2.0),result(area:198),sides(rectsides: 4)] for object in objects { if let objectWithArea = object as? rectangle { print("Area is \(objectWithArea.area)") } else { print("Rectangle area is not defined") } }
当我们使用游乐场运行上述程序时,会得到以下结果:
Area is 12.5663708 Area is 198.0 Rectangle area is not defined
Swift - 泛型
Swift 4 语言提供“泛型”功能来编写灵活且可重用的函数和类型。泛型用于避免重复并提供抽象。Swift 4 标准库是用泛型代码构建的。Swift 4 的“数组”和“字典”类型属于泛型集合。借助数组和字典,可以定义数组以保存“Int”值和“String”值或任何其他类型。
func exchange(a: inout Int, b: inout Int) { let temp = a a = b b = temp } var numb1 = 100 var numb2 = 200 print("Before Swapping values are: \(numb1) and \(numb2)") exchange(a: &numb1, b: &numb2) print("After Swapping values are: \(numb1) and \(numb2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Before Swapping values are: 100 and 200 After Swapping values are: 200 and 100
泛型函数:类型参数
泛型函数可用于访问任何数据类型,例如“Int”或“String”。
func exchange<T>(a: inout T, b: inout T) { let temp = a a = b b = temp } var numb1 = 100 var numb2 = 200 print("Before Swapping Int values are: \(numb1) and \(numb2)") exchange(a: &numb1, b: &numb2) print("After Swapping Int values are: \(numb1) and \(numb2)") var str1 = "Generics" var str2 = "Functions" print("Before Swapping String values are: \(str1) and \(str2)") exchange(a: &str1, b: &str2) print("After Swapping String values are: \(str1) and \(str2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Before Swapping Int values are: 100 and 200 After Swapping Int values are: 200 and 100 Before Swapping String values are: Generics and Functions After Swapping String values are: Functions and Generics
函数 exchange() 用于交换值,如上述程序中所述,<T> 用作类型参数。第一次调用函数 exchange() 将返回“Int”值,第二次调用函数 exchange() 将返回“String”值。可以在尖括号内包含多个参数类型,并用逗号分隔。
类型参数被命名为用户定义的,以了解其保存的类型参数的目的。Swift 4 提供 <T> 作为泛型类型参数名称。但是,像数组和字典这样的类型参数也可以命名为键、值,以识别它们属于“字典”类型。
struct TOS<T> { var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } } var tos = TOS<String>() tos.push(item: "Swift 4") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Type Parameters") print(tos.items) tos.push(item: "Naming Type Parameters") print(tos.items) let deletetos = tos.pop()
当我们使用游乐场运行上述程序时,会得到以下结果:
[Swift 4] [Swift 4, Generics] [Swift 4, Generics, Type Parameters] [Swift 4, Generics, Type Parameters, Naming Type Parameters]
扩展泛型类型
扩展 stack 属性以了解项目的顶部是否包含“extension”关键字。
struct TOS<T> { var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } } var tos = TOS<String>() tos.push(item: "Swift 4") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Type Parameters") print(tos.items) tos.push(item: "Naming Type Parameters") print(tos.items) extension TOS { var first: T? { return items.isEmpty ? nil : items[items.count - 1] } } if let first = tos.first { print("The top item on the stack is \(first).") }
当我们使用游乐场运行上述程序时,会得到以下结果:
["Swift 4"] ["Swift 4", "Generics"] ["Swift 4", "Generics", "Type Parameters"] ["Swift 4", "Generics", "Type Parameters", "Naming Type Parameters"] The top item on the stack is Naming Type Parameters.
类型约束
Swift 4 语言允许“类型约束”指定类型参数是否继承自特定类,或确保协议一致性标准。
func exchange<T>(a: inout T, b: inout T) { let temp = a a = b b = temp } var numb1 = 100 var numb2 = 200 print("Before Swapping Int values are: \(numb1) and \(numb2)") exchange(a: &numb1, b: &numb2) print("After Swapping Int values are: \(numb1) and \(numb2)") var str1 = "Generics" var str2 = "Functions" print("Before Swapping String values are: \(str1) and \(str2)") exchange(a: &str1, b: &str2) print("After Swapping String values are: \(str1) and \(str2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
Before Swapping Int values are: 100 and 200 After Swapping Int values are: 200 and 100 Before Swapping String values are: Generics and Functions After Swapping String values are: Functions and Generics
关联类型
Swift 4 允许在协议定义中通过关键字“associatedtype”声明关联类型。
protocol Container { associatedtype ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } } struct TOS<T>: Container { // original Stack<T> implementation var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { self.push(item: item) } var count: Int { return items.count } subscript(i: Int) -> T { return items[i] } } var tos = TOS<String>() tos.push(item: "Swift 4") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Type Parameters") print(tos.items) tos.push(item: "Naming Type Parameters") print(tos.items)
当我们使用游乐场运行上述程序时,会得到以下结果:
[Swift 4] [Swift 4, Generics] [Swift 4, Generics, Type Parameters] [Swift 4, Generics, Type Parameters, Naming Type Parameters]
where 子句
类型约束使用户能够定义与泛型函数或类型关联的类型参数的要求。为了定义关联类型的要求,“where”子句被声明为类型参数列表的一部分。“where”关键字紧跟在类型参数列表之后,然后是关联类型的约束、类型和关联类型之间的相等关系。
protocol Container { associatedtype ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } } struct Stack<T>: Container { // original Stack<T> implementation var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { self.push(item: item) } var count: Int { return items.count } subscript(i: Int) -> T { return items[i] } } func allItemsMatch< C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> (someContainer: C1, anotherContainer: C2) -> Bool { // check that both containers contain the same number of items if someContainer.count != anotherContainer.count { return false } // check each pair of items to see if they are equivalent for i in 0..<someContainer.count { if someContainer[i] != anotherContainer[i] { return false } } // all items match, so return true return true } var tos = Stack<String>() tos.push(item: "Swift 4") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Where Clause") print(tos.items) var eos = ["Swift 4", "Generics", "Where Clause"] print(eos)
当我们使用游乐场运行上述程序时,会得到以下结果:
[Swift 4] [Swift 4, Generics] [Swift 4, Generics, Where Clause] [Swift 4, Generics, Where Clause]
Swift - 访问控制
通过访问控制来限制对代码块、模块和抽象的访问。类、结构和枚举可以通过访问控制机制根据其属性、方法、初始化程序和下标进行访问。协议中的常量、变量和函数受到限制,并允许通过访问控制全局和本地访问。应用于属性、类型和函数的访问控制可以称为“实体”。
访问控制模型基于模块和源文件。
模块定义为代码分发的单个单元,可以使用关键字“import”导入。源文件定义为模块中的单个源代码文件,以访问多个类型和函数。
Swift 4 语言提供了三种不同的访问级别。它们是 Public、Internal 和 Private 访问。
序号 | 访问级别和定义 |
---|---|
1 | Public 使实体能够在来自其定义模块的任何源文件中处理,以及来自导入定义模块的其他模块的源文件。 |
2 | Internal 使实体能够在来自其定义模块的任何源文件中使用,但不能在该模块之外的任何源文件中使用。 |
3 | Private 将实体的使用限制在其自己的定义源文件中。Private 访问在隐藏特定代码功能的实现细节方面发挥作用。 |
语法
public class SomePublicClass {} internal class SomeInternalClass {} private class SomePrivateClass {} public var somePublicVariable = 0 internal let someInternalConstant = 0 private func somePrivateFunction() {}
函数类型的访问控制
某些函数可能在函数内部声明参数,没有任何返回值。以下程序将 a 和 b 声明为 sum() 函数的参数。在函数本身内部,通过调用函数调用 sum() 并打印其值来传递参数 a 和 b 的值,从而消除返回值。要将函数的返回类型设为 private,请使用 private 修饰符声明函数的整体访问级别。
private func sum(a: Int, b: Int) { let a = a + b let b = a - b print(a, b) } sum(a: 20, b: 10) sum(a: 40, b: 10) sum(a: 24, b: 6)
当我们使用游乐场运行上述程序时,会得到以下结果:
30 20 50 40 30 24
枚举类型的访问控制
public enum Student { case Name(String) case Mark(Int,Int,Int) } var studDetails = Student.Name("Swift 4") var studMarks = Student.Mark(98,97,95) switch studMarks { case .Name(let studName): print("Student name is: \(studName).") case .Mark(let Mark1, let Mark2, let Mark3): print("Student Marks are: \(Mark1),\(Mark2),\(Mark3).") }
当我们使用游乐场运行上述程序时,会得到以下结果:
Student Marks are: 98,97,95
Swift 4 语言中的枚举会自动为枚举的各个情况接收相同的访问级别。例如,考虑访问学生姓名和三门科目获得的分数,枚举名称声明为 student,enum 类中存在的成员是属于字符串数据类型的 name,分数表示为数据类型 Integer 的 mark1、mark2 和 mark3。要访问学生的姓名或他们获得的分数。现在,switch case 将打印学生姓名(如果该 case 块被执行),否则它将打印学生获得的分数。如果两个条件都失败,则将执行 default 块。
子类的访问控制
Swift 4 允许用户对可以在当前访问上下文中访问的任何类进行子类化。子类不能具有比其超类更高的访问级别。用户被限制编写内部超类的公共子类。
public class cricket { internal func printIt() { print("Welcome to Swift 4 Super Class") } } internal class tennis: cricket { override internal func printIt() { print("Welcome to Swift 4 Sub Class") } } let cricinstance = cricket() cricinstance.printIt() let tennisinstance = tennis() tennisinstance.printIt()
当我们使用游乐场运行上述程序时,会得到以下结果:
Welcome to Swift Super Class Welcome to Swift Sub Class
常量、变量、属性和下标的访问控制
Swift 4 常量、变量或属性不能定义为比其类型更公开。编写具有私有类型的公共属性是无效的。类似地,下标不能比其索引或返回类型更公开。
当常量、变量、属性或下标使用私有类型时,常量、变量、属性或下标也必须标记为 private:
private var privateInstance = SomePrivateClass()
getter 和 setter
常量、变量、属性和下标的 getter 和 setter 自动接收与其所属的常量、变量、属性或下标相同的访问级别。
class Samplepgm { var counter: Int = 0{ willSet(newTotal) { print("Total Counter is: \(newTotal)") } didSet { if counter > oldValue { print("Newly Added Counter \(counter - oldValue)") } } } } let NewCounter = Samplepgm() NewCounter.counter = 100 NewCounter.counter = 800
当我们使用游乐场运行上述程序时,会得到以下结果:
Total Counter is: 100 Newly Added Counter 100 Total Counter is: 800 Newly Added Counter 700
初始化程序和默认初始化程序的访问控制
自定义初始化程序可以分配小于或等于其初始化的类型的访问级别。必需的初始化程序必须与其所属的类具有相同的访问级别。初始化程序参数的类型不能比初始化程序自己的访问级别更私有。
要声明初始化器的每个子类,“required”关键字需要在 init() 函数之前定义。
class classA { required init() { let a = 10 print(a) } } class classB: classA { required init() { let b = 30 print(b) } } let res = classA() let print = classB()
当我们使用游乐场运行上述程序时,会得到以下结果:
10 30 10
默认初始化程序与其初始化的类型具有相同的访问级别,除非该类型定义为 public。当默认初始化程序定义为 public 时,它被认为是 internal。当用户需要在另一个模块中使用无参数初始化程序初始化公共类型时,请在类型的定义中显式提供公共无参数初始化程序。
协议的访问控制
当我们定义一个新的协议来从现有的协议继承功能时,两者都必须声明相同的访问级别才能继承彼此的属性。Swift 4 访问控制不允许用户定义一个从“internal”协议继承的“public”协议。
public protocol tcpprotocol { init(no1: Int) } public class mainClass { var no1: Int // local storage init(no1: Int) { self.no1 = no1 // initialization } } class subClass: mainClass, tcpprotocol { var no2: Int init(no1: Int, no2 : Int) { self.no2 = no2 super.init(no1:no1) } // Requires only one parameter for convenient method required override convenience init(no1: Int) { self.init(no1:no1, no2:0) } } let res = mainClass(no1: 20) let print = subClass(no1: 30, no2: 50) print("res is: \(res.no1)") print("res is: \(print.no1)") print("res is: \(print.no2)")
当我们使用游乐场运行上述程序时,会得到以下结果:
res is: 20 res is: 30 res is: 50
扩展的访问控制
当用户使用扩展来添加协议一致性时,Swift 4 不允许用户为扩展提供显式访问级别修饰符。扩展中每个协议要求实现的默认访问级别由其自己的协议访问级别提供。
泛型的访问控制
泛型允许用户指定最小访问级别以访问其类型参数上的类型约束。
public struct TOS<T> { var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } } var tos = TOS<String>() tos.push(item: "Swift 4") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Type Parameters") print(tos.items) tos.push(item: "Naming Type Parameters") print(tos.items) let deletetos = tos.pop()
当我们使用游乐场运行上述程序时,会得到以下结果:
[Swift 4] [Swift 4, Generics] [Swift 4, Generics, Type Parameters] [Swift 4, Generics, Type Parameters, Naming Type Parameters]
类型别名的访问控制
用户可以定义类型别名来处理不同的访问控制类型。用户可以定义相同的访问级别或不同的访问级别。当类型别名为“private”时,其关联成员可以声明为“private、internal 或 public 类型”。当类型别名为 public 时,成员不能别名为“internal”或“private”名称
为访问控制目的,您定义的任何类型别名都被视为不同的类型。类型别名的访问级别可以小于或等于其别名类型的访问级别。例如,私有类型别名可以别名私有、内部或公共类型,但公共类型别名不能别名内部或私有类型。
public protocol Container { associatedtype ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } } struct Stack<T>: Container { // original Stack<T> implementation var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { self.push(item: item) } var count: Int { return items.count } subscript(i: Int) -> T { return items[i] } } func allItemsMatch< C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> (someContainer: C1, anotherContainer: C2) -> Bool { // check that both containers contain the same number of items if someContainer.count != anotherContainer.count { return false } // check each pair of items to see if they are equivalent for i in 0..<someContainer.count { if someContainer[i] != anotherContainer[i] { return false } } // all items match, so return true return true } var tos = Stack<String>() tos.push(item: "Swift 4") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Where Clause") print(tos.items) var eos = ["Swift 4", "Generics", "Where Clause"] print(eos)
当我们使用游乐场运行上述程序时,会得到以下结果:
[Swift 4] [Swift 4, Generics] [Swift 4, Generics, Where Clause] [Swift 4, Generics, Where Clause]
Swift 编码和解码
Swift 4 引入了一个新的Codable协议,它允许您序列化和反序列化自定义数据类型,而无需编写任何特殊代码,并且无需担心丢失值类型。
struct Language: Codable { var name: String var version: Int } let swift = Language(name: "Swift", version: 4) let java = Language(name: "java", version: 8) let R = Language(name: "R", version: 3
请注意,Langauage 符合 Codable 协议。现在,我们将使用一行简单的代码将其转换为 Json 数据表示形式。
let encoder = JSONEncoder() if let encoded = try? encoder.encode(java) { //Perform some operations on this value. }
Swift 将自动编码数据类型中的所有值。
您可以使用 Decoder 函数解码数据,例如
let decoder = JSONDecoder() if let decoded = try? decoder.decode(Language.self, from: encoded) { //Perform some operations on this value. }
JSONEncoder 及其属性列表对应物 PropertyListEncoder 具有许多用于自定义其工作方式的选项。