swift基础学习
基础教程参考
对于纯白色的小白可以完全参照下面swift菜鸟教程
和Swift 中文手册(3.0)
去学习一遍。
一些容易忽视的注意点
标识符、数据类型
- 如果一定要使用关键字作为标识符,可以在关键字前后添加重音符号(`),例如:
let `class` = "ssss"
- 在Swift中,运算符不能直接跟在变量或常量的后面。例如下面的代码会报错:
//等号与a没有空开
let a= 1 + 2
-
数据类型包括:
Int、UInt、Float、Double、Bool、String、Array、Dictionary、Character(字符)、Optional(可选类型)、Struct、Class
等 -
类型别名对当前的类型定义了另一个名字,类型别名通过使用 typealias 关键字来定义。语法格式如下:
typealias newname = type
//定义了 Int 的类型别名为 Feet:
typealias Feet = Int
-
类型安全:Swift 是一个类型安全(type safe)的语言。由于 Swift 是类型安全的,所以它会在编译你的代码时进行类型检查(type checks),并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误。
-
类型推断:当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说你每次声明常量和变量的时候都需要显式指定类型。如果你没有显式指定类型,Swift 会使用类型推断(type inference)来选择合适的类型。
let meaningOfLife = 42
// meaningOfLife 会被推测为 Int 类型
- 类型标注:你声明常量或者变量的时候可以加上类型标注(type annotation),说明常量或者变量中要存储的值的类型。如果要添加类型标注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。
var constantName:<data type> = <optional initial value>
//例如
var str : String = "sss"
let num : Int = 10
可选类型、强制解析、自动解析、可选绑定
- Swift 的可选(Optional)类型:用于处理值缺失的情况。可选表示"那儿有一个值,并且它等于 x “或者"那儿没有值”。Swfit语言定义后缀?作为命名类型Optional的简写,换句话说,以下两种声明是相等的:
var optionalInteger: Int?
var optionalInteger: Optional<Int>
Optional 是一个含有两种情况的枚举,None 和 Some(T),用来表示可能有或可能没有值。任何类型都可以明确声明为(或者隐式转换)可选类型。当声明一个可选类型的时候,要确保用括号给 ? 操作符一个合适的范围。当你声明一个可选变量或者可选属性的时候没有提供初始值,它的值会默认为 nil。可选项遵照 LogicValue 协议,因此可以出现在布尔环境中。在这种情况下,如果可选类型T?包含类型为T的任何值(也就是说它的值是 Optional.Some(T) ),这个可选类型等于 true,反之为 false。如果一个可选类型的实例包含一个值,你可以用后缀操作符 !来访问这个值.使用操作符!去获取值为nil的可选变量会有运行时错误。可选类型类似于Objective-C中指针的nil值,但是nil只对类(class)有用,而可选类型对所有的类型都可用,并且更安全。
- 强制解析:当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号(!)来获取值。这个感叹号表示"我知道这个可选有值,请使用它。"这被称为可选值的强制解析(forced unwrapping)。
var myString : String?
myString = "Hello, Swift!"
if myString != nil {
print(myString)
print(myString!)
}else{
print("myString 值为 nil")
}
var myString2 : Optional<String>
运行结果分别为:
Optional("Hello, Swift!")
Hello, Swift!
注意:使用!来获取一个不存在的可选值会导致运行时错误。使用!来强制解析值之前,一定要确定可选包含一个非nil的值。
- 自动解析:你可以在声明可选变量时使用感叹号(!)替换问号(?)。这样可选变量在使用时就不需要再加一个感叹号(!)来获取值,它会自动解析。
var myString3 : String!
myString3 = "Hello, Swift!"
if myString3 != nil {
print(myString3)
}else{
print("myString3 值为 nil")
}
可选绑定
: 使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。像下面这样在if语句中写一个可选绑定:
if let constantName = someOptional {
statements
}
你可以一行代码中包含多个可选值的绑定 用‘where’引起一个bool的判断条件 如果这些绑定可选值中的任何一个是nil 或者条件判断是nil 那么整个可选绑定值就被视为是不成功的
var myString:String?
myString = "Hello, Swift!"
if let yourString = myString {//如果myString有值,即不为nil,这时候默认解包了
print("你的字符串值为 - \(yourString)")
}else{
print("你的字符串没有值")
}
if let firstValue = Int("22222"),let secondValue = Int("452") , firstValue < secondValue {
print("\(firstValue) < \(secondValue)")
}else{
print("判断条件不成立")
}
注意:nil 不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失 的情况,请把它们声明成对应的可选类型。
运算符
- Swift 提供了两个区间的运算符:
- 闭区间运算符:闭区间运算符(a…b)定义一个包含从a到b(包括a和b)的所有值的区间,b必须大于等于a。 闭区间运算符在迭代一个区间的所有值时是非常有用的,如在for-in循环中。
- 半开区间运算符:半开区间(a…
print("闭区间运算符:")
for index in 1...5 {
print("\(index) * 5 = \(index * 5)")
}
print("半开区间运算符:")
for index in 1..<5 {
print("\(index) * 5 = \(index * 5)")
}
- 运算符优先级:
指针最优,单目运算优于双目运算。如正负号。
先乘除(模),后加减。
先算术运算,后移位运算,最后位运算。请特别注意:1 << 3 + 2 & 7 等价于 (1 << (3 + 2))&7。
逻辑运算最后计算。
数组、字典
- 数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。
//创建
let arr = ["s1","s2"]
let arr1:[String] = ["s1","s2"]
let arr2:Array<String> = ["s1","s2"]
//取值
arr[0]
arr2[1]
- 字典用来存储无序的相同类型数据的集合,Swift字典会强制检测元素的类型,如果类型不同则会报错。字典每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。字典的key没有类型限制可以是整型或字符串,但必须是唯一的。(key的类型必须唯一,值可以声明未任意类型)
let dic = [1:"标题",2:[1,2,3],] as [Int : Any]
let dic2: [String : Any] = ["title":"标题","data":[1,2,3],]
dic[1]
dic2["title"]
元组
- 元组(tuples)是由其它类型组合而成的类型。元组可能包含零或多个类型,比如 字符串、整数、字符、布尔、数组、字典以及其它元组等。同时请注意,元组是值传递,而不是引用。在Swift中创建元组的方式很简单,元组类型是用括号包围,由一个逗号分隔的零个或多个类型的列表。
let tuples1 = ("Mary", 9001,18.0,[12,13,14],[1:"字典"],(1,"其他元组"))
在创建元组时你还可以给元组中的元素命名(可以部分命名也可以全部命名)
let tuples2 = (str : "Mary", 9001,18.0,arr : [12,13,14],dic : [1:"字典"],tuples : (1,"其他元组"))
你只需要把你想用的、任何类型的值放在圆括号内,用逗号隔开即可。如果你愿意你还可以给每个元素命名,提高元组使用效率。
- 从元组中读元素
如果我们没有给元组的元素命名,我们可以用点语法,通过定义好的元组变量或常量获取它的第1个到第n个元素
//获取匿名元素
tuples1.0
tuples1.5
//获取命名元素(可以通过名称取出也可以通过脚表取出)
tuples2.str
tuples2.0
tuples2.tuples.1
如果你觉得上述这种方法会造成语义的不明确,那么我们还可以将元组赋值给一个带有元素名称的元组(元素名称个数要对应):
let (a,b,c,d,e,f) = tuples1
print(a)
print(e)
如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线(_)标记:
let (_,b,_,d,e,_) = tuples1
print(b)
print(d)
- 元组作为函数返回值
当一个函数有多个返回值时,可以用元组作为函数返回值:
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)
}
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("最小值为 \(bounds.min) ,最大值为 \(bounds.max)")
如果你不确定返回的元组一定不为nil,那么你可以返回一个可选的元组类型。你可以通过在元组类型的右括号后放置一个问号来定义一个可选元组,例如(Int, Int)?或(String, Int, Bool)?
注意:可选元组类型如(Int, Int)?与元组包含可选类型如(Int?, Int?)是不同的.可个元组是可选的选的元组类型,整,而不只是元组中的每个元素值。
//可能没值
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: []) {
print("最小值为 \(bounds.min),组大值为 \(bounds.max)")
}else{
print("传进来的事一个空数组,返回值未nil")
}
闭包
- 闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。全局函数和嵌套函数其实就是特殊的闭包。
- 以下定义了一个接收参数并返回指定类型的闭包语法:
{(parameters) -> return type in
statements
}
let studname = { print("Swift 闭包实例。") }
studname()
//类似函数
let divide = {(val1: Int, val2: Int) -> Int in
return val1 / val2
}
let result = divide(200, 20)
print (result)
- 尾随闭包
尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函数体部分
}
// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
// 闭包主体部分
})
// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
// 闭包主体部分
}
- 捕获值
闭包可以在其定义的上下文中捕获常量或变量。即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数。嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
// 返回的值为10
print(incrementByTen())
// 返回的值为20
print(incrementByTen())
// 返回的值为30
print(incrementByTen())
//闭包和函数一样都是引用类型,
let alsoIncrementByTen = incrementByTen
// 返回的值和incrementByTen一样都是30
print(alsoIncrementByTen())
枚举
- 枚举简单的说也是一种数据类型,只不过是这种数据类型只包含自定义的特定数据,它是一组有共同特性的数据的集合。
Swift 的枚举类似于 Objective C 和 C 的结构,枚举的功能为:
- 它声明在类中,可以通过实例化类来访问它的值。
- 枚举也可以定义构造函数(initializers)来提供一个初始成员值;可以在原始的实现基础上扩展它们的功能。
- 可以遵守协议(protocols)来提供标准的功能。
- Swift 中使用 enum 关键词来创建枚举并且把它们的整个定义放在一对大括号内:
enum enumname {
// 枚举定义放在这里
}
// 定义枚举
enum DaysofaWeek {
case Sunday
case Monday
case TUESDAY
case WEDNESDAY
case THURSDAY
case FRIDAY
case Saturday
}
var weekDay = DaysofaWeek.THURSDAY
weekDay = .THURSDAY
switch weekDay
{
case .Sunday:
print("星期天")
case .Monday:
print("星期一")
case .TUESDAY:
print("星期二")
case .WEDNESDAY:
print("星期三")
case .THURSDAY:
print("星期四")
case .FRIDAY:
print("星期五")
case .Saturday:
print("星期六")
枚举中定义的值(如 Sunday,Monday,……和Saturday)是这个枚举的成员值(或成员)。case关键词表示一行新的成员值将被定义。
注意: 和 C 和 Objective-C 不同,Swift 的枚举成员在被创建时不会被赋予一个默认的整型值。在上面的DaysofaWeek例子中,Sunday,Monday,……和Saturday不会隐式地赋值为0,1,……和6。相反,这些枚举成员本身就有完备的值,这些值是已经明确定义好的DaysofaWeek类型。
- 相关值:是当你在创建一个基于枚举成员的新常量或变量时才会被设置,并且每次当你这么做得时候,它的值可以是不同的。
以下实例中我们定义一个名为 Student 的枚举类型,它可以是 Name 的一个字符串(String),或者是 Mark 的一个相关值(Int,Int,Int)。
import Cocoa
enum Student{
case Name(String)
case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Runoob")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
case .Name(let studName):
print("学生的名字是: \(studName)。")
case .Mark(let Mark1, let Mark2, let Mark3):
print("学生的成绩是: \(Mark1),\(Mark2),\(Mark3)。")
}
- 原始值:原始值可以是字符串,字符,或者任何整型值或浮点型值。每个原始值在它的枚举声明中必须是唯一的。在原始值为整数的枚举时,不需要显式的为每一个成员赋值,Swift会自动为你赋值。例如,当使用整数作为原始值时,隐式赋值的值依次递增1。如果第一个值没有被赋初值,将会被自动置为0。
enum Month: Int {
case January = 1, February, March, April, May, June, July, August, September, October, November, December
}
let yearMonth = Month.May.rawValue
//数字月份为:5
print("数字月份为: \(yearMonth)。")
类
- Swift类是构建代码所用的一种通用且灵活的构造体。我们可以为类定义属性(常量、变量)和方法。与其他编程语言所不同的是,Swift 并不要求你为自定义类去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类,系统会自动生成面向其它代码的外部接口。
- Swift中类和结构体有很多共同点。共同处在于:
- 定义属性用于存储值
- 定义方法用于提供功能
- 定义附属脚本用于访问值
- 定义构造器用于生成初始化值
- 通过扩展以增加默认实现的功能
- 符合协议以对某类提供标准功能
- 与结构体相比,类还有如下的附加功能:
- 继承允许一个类继承另一个类的特征
- 类型转换允许在运行时检查和解释一个类实例的类型
- 解构器允许一个类实例释放任何其所被分配的资源
- 引用计数允许对一个类的多次引用
- 语法
class classname {
Definition 1
Definition 2
……
Definition N
}
//定义类
class SampleClass: Equatable {
let myProperty: String
let parm : Int
//可以用构造函数在初始化时,给属性设置一些默认的值
init(s: String ,p: Int) {
myProperty = s
self.parm = p
}
func test() {
print("SampleClass类中的方法")
}
}
//定义一个方法比较是不是同一个类
func ==(lhs: SampleClass, rhs: SampleClass) -> Bool {
return lhs.myProperty == rhs.myProperty
}
let spClass1 = SampleClass(s: "Hello",p:1)
let spClass2 = SampleClass(s: "Hello",p:1)
let spClass3 = spClass1
//恒等运算符 :如果两个常量或者变量引用同一个类实例则返回 true
if spClass1 === spClass2 {// false
print("引用相同的类实例 \(spClass1)")
}
//不恒等运算符 : 如果两个常量或者变量引用不同一个类实例则返回 true
if spClass1 !== spClass2 {// true
print("引用不相同的类实例 \(spClass2)")
}
if spClass1 === spClass3 {// true
print("引用相同的类实例 \(spClass1)")
}
//访问类中的属性
spClass3.parm
//访问类中的方法
spClass3.test()
属性
- Swift属性将值跟特定的类、结构或枚举关联。属性可分为
存储属性
和计算属性
,储属性和计算属性通常用于特定类型的实例;属性也可以直接用于类型本身,这种属性称为类型属性
。 - 存储属性:简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。存储属性可以是变量存储属性(用关键字var定义),也可以是常量存储属性(用关键字let定义)。
//结构体
struct Number
{
var digits: Int
let pi = 3.1415
}
var n = Number(digits: 12345)
n.digits = 67
n.pi
//类
class Test
{
var digits: Int = 0
var s: Float
init(x:Float) {
s = x
}
let pi = 3.1415
}
let t = Test(x: 20)
t.digits = 20
- 延迟存储属性:延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用
lazy
来标示一个延迟存储属性。
注意:必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
延迟存储属性一般用于:延迟对象的创建、当属性的值依赖于其他未知类。
class sample {
lazy var no = number() // `var` 关键字是必须的
}
class number {
var name = "Runoob Swift 教程"
}
var firstsample = sample()
print(firstsample.no.name)
- 计算属性:除存储属性外,类、结构体和枚举可以定义计算属性,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。
class sample {
var no1 = 0.0, no2 = 0.0,length = 300.0, breadth = 150.0
//只传前两个属性
var middle: (Double, Double) {
get{
return (length / 2, breadth / 2)
}
set(axis){
//axis.0 等价与no1,axis.1等价于no2
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)
- 只读计算属性:只有 getter 没有 setter 的计算属性就是只读计算属性。只读计算属性总是返回一个值,可以通过点(.)运算符访问,但不能设置新的值。
class film {
var head = "sss"
var duration = 0.0
//metaInfo是一个只读属性
var metaInfo: [String:String]{//闭包
return [
"head": self.head,
"duration":"\(self.duration)"
]
}
}
var movie = film()
movie.head = "Swift 属性"
movie.duration = 3.09
print(movie.metaInfo["head"]!)
print(movie.metaInfo["duration"]!)
- 属性观察器:属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。不需要为无法重载的计算属性添加属性观察器,因为可以通过 setter 直接监控和响应值的变化。
- willSet在设置新的值之前调用(可以调用newTotal)
- didSet在新的值被设置之后立即调用(可以调用oldValue)
- willSet和didSet观察器在属性初始化过程中不会被调用
class Samplepgm {
var counter: Int = 0{
willSet(newTotal){
print("计数器新值: \(newTotal)")
}
didSet{
print("新增数旧值 \(oldValue)")
if counter > oldValue {
print("新增数 \(counter - oldValue)")
}
}
}
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
- 类型属性:类型属性是作为类型定义的一部分写在类型最外层的花括号({})内。使用关键字 static 来定义值类型的类型属性,关键字 class 来为类定义类型属性。
struct Structname {
static var storedTypeProperty = " "
static var computedTypeProperty: Int {
// 这里返回一个 Int 值
}
}
enum Enumname {
static var storedTypeProperty = " "
static var computedTypeProperty: Int {
// 这里返回一个 Int 值
}
}
class Classname {
class var computedTypeProperty: Int {
// 这里返回一个 Int 值
}
}
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
//设置类属性
StudMarks.totalCount = 100
//获取实例属性
print(stud1Mark1.InternalMarks)
//获取类属性
print(StudMarks.markCount)
print(StudMarks.totalCount)
方法
-
Swift方法是与某些特定类型相关联的函数,在 Objective-C 中,类是唯一能定义方法的类型。但在 Swift 中,你不仅能选择是否要定义一个类/结构体/枚举,还能灵活的在你创建的类型(类/结构体/枚举)上定义方法。
-
实例方法 : 于某个特定类、结构体或者枚举类型实例的方法。方法的局部参数名称和外部参数名称,可以使用下划线_做匿名参数
func funcname(Parameters) -> returntype
{
Statement1
Statement2
……
Statement N
return parameters
}
struct area {
var length = 1
var breadth = 1
func area() -> Int {
return length * breadth
}
//Swift 语言中结构体和枚举是值类型。一般情况下,值类型的属性不能在它的实例方法中被修改。你可以选择变异(mutating)这个方法,然后方法就可以从方法内部改变它的属性
mutating func scaleBy(res: Int) {
length *= res
self.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)
- 类型方法:实例方法是被类型的某个实例调用的方法,你也可以定义类型本身调用的方法,这种方法就叫做类型方法。声明结构体和枚举的类型方法,在方法的func关键字之前加上关键字static。类可能会用关键字class来允许子类重写父类的实现方法。类型方法和实例方法一样用点号(.)语法调用。
struct absno
{
static func abs(number: Int) -> Int
{
if number < 0
{
return (-number)
}
else
{
return number
}
}
}
let num = absno.abs(number: -5)
print(num)
- 下标脚本语法及应用:下标脚本 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法。与定义实例方法类似,定义下标脚本使用subscript关键字,显式声明入参(一个或多个)和返回类型。
struct subexample {
let decrementer: Int
subscript(index: Int) -> Int {
return decrementer / index
}
}
let division = subexample(decrementer: 100)
print("100 除以 9 等于 \(division[9])")
print("100 除以 2 等于 \(division[2])")
print("100 除以 3 等于 \(division[3])")
print("100 除以 5 等于 \(division[5])")
print("100 除以 7 等于 \(division[7])")
- 通常下标脚本是用来访问集合(collection),列表(list)或序列(sequence)中元素的快捷方式。
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])
- 要想重写父类的方法,需要在方法前面加上
overriding
关键字。 - 你可以通过在关键字
class
前添加final
特性(final class)
来将整个类标记为final
的,这样的类是不可被继承的,否则会报编译错误。 - 构造过程是为了使用某个类、结构体或枚举类型的实例而进行的准备过程。这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务。
Swift 构造函数使用 init() 方法
。 - 在一个类的实例被释放之前,析构函数被立即调用。用关键字
deinit
来标示析构函数,类似于初始化函数用init
来标示。析构函数只适用于类类型。
Swift 扩展
- 扩展就是向一个已有的类、结构体或枚举类型添加新功能。扩展可以对一个类型添加新的功能,但是不能重写已有的功能。
- Swift 中的扩展可以:
- 添加计算型属性和计算型静态属性
- 定义实例方法和类型方法
- 提供新的构造器提供新的构造器
- 定义下标定义下标
- 定义和使用新的嵌套类型
- 使一个已有类型符合某个协议
- 扩展声明使用关键字 extension:
extension SomeType {
// 加到SomeType的新功能写到这里
}
- 一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议,语法格式如下:
extension SomeType: SomeProtocol, AnotherProctocol {
// 协议实现写到这里
}
struct sum {
var num1 = 100, num2 = 200
}
struct diff {
var no1 = 200, no2 = 100
}
struct mult {
var a = sum()
var b = diff()
var c : Int?
var d : Int?
}
extension mult {
init(x: sum, y: diff) {
c = x.num1 + x.num2
d = y.no1 + y.no2
}
}
let a = sum(num1: 100, num2: 200)
let b = diff(no1: 200, no2: 100)
let getMult = mult(x: a, y: b)
//扩展方法
extension Int {
func topics(summation: () -> ()) {
for _ in 0..<self {
summation()
}
}
}
3.topics(summation: {
print("扩展模块内")
})
3.topics(summation: {
print("内型转换模块内")
})
泛型
- Swift 提供了泛型让你写出灵活且可重用的函数和类型。Swift 标准库是通过泛型代码构建出来的。Swift 的数组和字典类型都是泛型集。
- 功能代码是相同的,只是类型上不一样,这时我们可以使用泛型,从而避免重复编写代码。泛型使用了占位类型名(在这里用字母 S 来表示)来代替实际类型名(例如 Int、String 或 Double)。
func swapTwoValues<S>(_ a: inout S, _ b: inout S)
func swapTwoValues<S>(_ a: inout S, _ b: inout S) {
let temporaryA = a
a = b
b = temporaryA
}
var numb1 = 100
var numb2 = 200
print("交换前数据: \(numb1) 和 \(numb2)")
swapTwoValues(&numb1, &numb2)
print("交换后数据: \(numb1) 和 \(numb2)")
var str1 = "A"
var str2 = "B"
print("交换前数据: \(str1) 和 \(str2)")
swapTwoValues(&str1, &str2)
print("交换后数据: \(str1) 和 \(str2)")