问:传值调用与传引用调用的区别
答:一般默认的参数传递都是传值调用的,而不是传引用。所以传入的参数在函数内改变,并不影响原来的那个参数。传入的只是这个参数的副本。当传入的参数作为输入输出参数时,需要在参数名前加 & 符,表示这个值可以被函数修改。
问:常量,变量及 I/O 参数
答:一般默认在函数中定义的参数都是常量参数,也就是这个参数你只可以查询使用,不能改变它的值。
如果想要声明一个变量参数,可以在参数定义前加 inout 关键字,这样就可以改变这个参数的值了。
例如:
func getName(_ name: inout String).........
此时这个 name 值可以在函数中改变。
一般默认的参数传递都是传值调用的,而不是传引用。所以传入的参数在函数内改变,并不影响原来的那个参数。传入的只是这个参数的副本。
当传入的参数作为输入输出参数时,需要在参数名前加 & 符,表示这个值可以被函数修改。
实例
import Cocoa
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var x = 1
var y = 5
swapTwoInts(&x, &y)
print("x 现在的值 \(x), y 现在的值 \(y)")
swapTwoInts(::) 函数简单地交换 a 与 b 的值。该函数先将 a 的值存到一个临时常量 temporaryA 中,然后将 b 的值赋给 a,最后将 temporaryA 赋值给 b。
需要注意的是,someInt 和 anotherInt 在传入 swapTwoInts(::) 函数前,都加了 & 的前缀。
以上程序执行输出结果为:
x 现在的值 5, y 现在的值 1
问:函数--嵌套函数
定义在函数体中的函数,称为嵌套函数(nested functions)。
默认情况下,嵌套函数是对外是不可见的,但可以被封闭他们的函数(enclosing function)调用。封闭函数可以返回它的一个嵌套函数,使这个函数在其他域中可以被使用。
func chooseStep(step : Bool)->(Int)->String{
func stepForward(input : Int)->String{
return String(input+2)
}
func stepBackward(input :Int) ->String{
return String(input-2)
}
return step ? stepBackward : stepForward
}
定义函数 chooseStep ,有一个Bool型的参数 step 他的返回值类型 为 ->(Int)->String
函数体内 包含了两个函数 stepForward 和 stepBackward
return 语句是一个 三木运算,step 为 true 时返回 setpBackward函数 ;step 为 false 时 返回 stepForward
接下来调用这个函数
var currentValue = 3
let next = chooseStep(currentValue>0)
当我们调用函数 chooseStep 的时候返回的不一个具体的值,而是一个函数的指针,这个指针指向了常量 next。所以说,next 是个函数。具体是哪个函数呢?
在我们调用的chooseStep函数的时候,传入(currentValue > 0)3 > 0 为 true 。返回的是stepBackward这个函数的指针,所以next 就相当于是 stepBackward 函数。
接下来调用 next 函数
var nextValue = next(currentValue)
print(nextValue)
现在调用 next 函数,就是在调用 stepBackward 函数,参数为 Int ,返回值为String
回头再来看chooseStep 函数 ,他的返回值类型 。->(Int)->String 这里的Int 就是 嵌套函数 的参数类型。String就是 嵌套函数的返回值类型
问:闭包知识点总结
全局函数 | 嵌套函数 | 闭包表达式 |
---|---|---|
有名字但不能捕获任何值 | 有名字,也能捕获封闭函数内的值 | 无名闭包,使用轻量级语法,可以根据上下文环境捕获值。 |
闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。
Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 匿名函数比较相似。
全局函数和嵌套函数其实就是特殊的闭包。
闭包的形式有:
全局函数 | 嵌套函数 | 闭包表达式 |
---|---|---|
有名字但不能捕获任何值 | 有名字,也能捕获封闭函数内的值 | 无名闭包,使用轻量级语法,可以根据上下文环境捕获值。 |
Swift中的闭包有很多优化的地方:
1.根据上下文推断参数和返回值类型
2.从单行表达式闭包中隐式返回(也就是闭包体只有一行代码,可以省略return)
3.可以使用简化参数名,如$0, $1(从0开始,表示第i个参数...)
4.提供了尾随闭包语法(Trailing closure syntax)
语法
以下定义了一个接收参数并返回指定类型的闭包语法:
{(parameters) -> return type in
statements
}
实例
import Cocoa
let studname = { print("Swift 闭包实例。") }
studname()
以上程序执行输出结果为
Swift 闭包实例。
以下闭包形式接收两个参数并返回布尔值
{(Int, Int) -> Bool in
Statement1
Statement 2
---
Statement n
}
实例
import Cocoa
let divide = {(val1: Int, val2: Int) -> Int in
return val1 / val2
}
let result = divide(200, 20)
print (result)
以上程序执行输出结果为:
10
捕获值
闭包可以在其定义的上下文中捕获常量或变量。
即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数。
嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。
看这个例子:
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
一个函数makeIncrementor ,它有一个Int型的参数amout, 并且它有一个外部参数名字forIncremet,意味着你调用的时候,必须使用这个外部名字。返回值是一个()-> Int的函数。
函数题内,声明了变量runningTotal 和一个函数incrementor。
incrementor函数并没有获取任何参数,但是在函数体内访问了runningTotal和amount变量。这是因为其通过捕获在包含它的函数体内已经存在的runningTotal和amount变量而实现。
由于没有修改amount变量,incrementor实际上捕获并存储了该变量的一个副本,而该副本随着incrementor一同被存储。
所以我们调用这个函数时会累加:
import Cocoa
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())
以上程序执行输出结果为
10
20
30
闭包是引用类型
上面的例子中,incrementByTen是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量值。
这是因为函数和闭包都是引用类型。
无论您将函数/闭包赋值给一个常量还是变量,您实际上都是将常量/变量的值设置为对应函数/闭包的引用。 上面的例子中,incrementByTen指向闭包的引用是一个常量,而并非闭包内容本身。
这也意味着如果您将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包
问:枚举
枚举简单的说也是一种数据类型,只不过是这种数据类型只包含自定义的特定数据,它是一组有共同特性的数据的集合。
Swift 的枚举类似于 Objective C 和 C 的结构,枚举的功能为:
1.它声明在类中,可以通过实例化类来访问它的值。
2.枚举也可以定义构造函数(initializers)来提供一个初始成员值;可以在原始的实现基础上扩展它们的功能。
3.可以遵守协议(protocols)来提供标准的功能。
语法
Swift 中使用 enum 关键词来创建枚举并且把它们的整个定义放在一对大括号内:
enum enumname {
// 枚举定义放在这里
}
例如我们定义以下表示星期的枚举:
import Cocoa
// 定义枚举
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类型。
weekDay的类型可以在它被DaysofaWeek的一个可能值初始化时推断出来。一旦weekDay被声明为一个DaysofaWeek,你可以使用一个缩写语法(.)将其设置为另一个DaysofaWeek的值:
var weekDay = .THURSDAY
当weekDay的类型已知时,再次为其赋值可以省略枚举名。使用显式类型的枚举值可以让代码具有更好的可读性。
枚举可分为相关值与原始值。
具体相关值与原始值的区别与用法不在此做说明,但是需要重点了解。
问:类和结构体对比
Swift 中类和结构体有很多共同点。共同处在于:
1.定义属性用于存储值
2.定义方法用于提供功能
3.定义附属脚本用于访问值
4.定义构造器用于生成初始化值
5.通过扩展以增加默认实现的功能
6.符合协议以对某类提供标准功能
与结构体相比,类还有如下的附加功能:
1.继承允许一个类继承另一个类的特征
2.类型转换允许在运行时检查和解释一个类实例的类型
3.解构器允许一个类实例释放任何其所被分配的资源
4.引用计数允许对一个类的多次引用
问:Swift 协议
类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。
尽管协议本身并不实现任何功能,但是协议可以被当做类型来使用。
协议可以像其他普通类型一样使用,使用场景:
1.作为函数、方法或构造器中的参数类型或返回值类型
2.作为常量、变量或属性的类型
3.作为数组、字典或其他容器中的元素类型
协议能够继承一个或多个其他协议,可以在继承的协议基础上增加新的内容要求。