# 第五章 Functions and Closures - 函数和闭包方法

237人阅读 评论(0)

Swift支持全局的函数和方法，函数关联的类和其他的类型等。Swift还支持闭包，类似于匿名函数的表达式。

## Your first function - 你的第一个函数

import Foundation
let a = 3.0, b = 4.0
let c = sqrt(a * a + b * b)
print(c) 

Swift中没有自带计算数值平方的函数，所以我们自己来写一个，更新playground。

import Foundation
func square(number: Double) -> Double {
return number * number;
}

let a = 3.0, b = 4.0
let c = sqrt(square(a) + square(b))
print(c) 

## Functions are first-class - 函数是最棒的类

func square(number: Double) -> Double {
return number * number
}

let operation = square
let a = 3.0, b = 4.0
let c = sqrt(operation(a) + operation(b))
print(c) 

let operation = square

let operation:(Double) -> Double = square 

square和operation都是（Double）->Double类型。这个函数类型说明了参数的类型和返回的类型（包括了参数的个数和类型）。这通常被称为函数的签名。和任何的函数一样，同样的签名都被认为是具有相同的类型。

func doMath(operation:(Double)-> Double) -> Double { … }

typealias OperationType = (Double) -> Double
func doMath(operation:OperationType) -> Double { … }

## Function syntax - 函数语法

func generateRandomNumber() -> Double { ... } 

func padString(string: String, length: Int) -> String { ... } 

func logDouble(number:Double) -> Void {
print(String(format: "%.2f", number))
}
logDouble(c) 

typealias Void = () 

func logDouble(number:Double) -> () {
print(String(format: "%.2f", number))
} 

func logDouble(number:Double) {
print(String(format: "%.2f", number))
} 

func logDouble(number:Double) {
print(String(format: "%.2f", number))
}

var logger: (Double) -> () = logDouble
logger(c) 

var logger: (Double) = logDouble 

func checkAreEqual(value: Int, expected: Int, message: String) {
if expected != value {
print(message)
}
}

var input = 3
checkAreEqual(input, expected: 2, message: "An input value of '2' was expected")
input = 47
checkAreEqual(input, expected: 47, message: "An input value of '47' was expected")

An input value of ‘2’ was expected

func checkAreEqual(value: String, expected: String, message: String) {
if expected != value {
print(message)
}
}

var inString = "cat"
checkAreEqual(inString, expected: "dog", message: "An input value of 'dog' was expected”)

An input value of ‘dog’ was expected

func checkAreEqual<T: Equatable>(value: T, expected: T, message: String) {
if expected != value {
print(message)
}
} 

1.传递到此函数时的第一个和第二个参数必须是相同类型，因为两个参数都用了相同的类型T。

2.必须采用Equatable协议类型。这个约束利用了!=运算符，是实现checkAreEqual的必须条件。

## In-out variables - 输入输出变量

import Foundation
func square(number: Double) {
number = number * number
}
var a = 2.0
square(a)
print(a) 

Cannot assign to ‘let’ value number.

fun square(inout number: Double) {
number = number * number
}
var a = 2.0
square(&a)
print(a)

## Classes and structures as function parameters - 类和结构做函数的参数

Swift在处理类上面有些不同，看下面的例子：

class Person {
var age = 34,
name = "Colin"
func growOlder() {
self.age+=1
}
}

func celebrateBirthday(cumpleanero: Person) {
print("Happy Birthday \(cumpleanero.name)")
cumpleanero.growOlder()
}
let person = Person()
celebrateBirthday(person)
print(person.age)

Happy Birthday Colin
35

struct Person {
var age = 34, name = "Colin"
mutating func growOlder() {
self.age+=1
}
} 

func celebrateBirthday(inout cumpleanero: Person) {

print("Happy Birthday \(cumpleanero.name)")
cumpleanero.growOlder()
}
var person = Person()
celebrateBirthday(&person)
print(person.age)

Happy Birthday Colin
35

func longestWord(words: String...) -> String?

func longestWord(words: String...) -> String? {
var currentLongest: String?
for word in words {
if currentLongest != nil {
if word.characters.count > currentLongest!.characters.count {
currentLongest = word
}
} else {
currentLongest = word
}
}
return currentLongest
}

let long = longestWord("chick", "fish", "cat", "elephant")
print(long) 

Optional(“elephant”)

func longestWord(words: String...) -> String? {
return words.reduce(String?()) {
(longest, word) in
longest == nil || word.characters.count > longest!.characters.count
? word : longest
}
}

## External parameter names - 外部参数名

checkAreEqual("cat", "dog", "Incorrect input") 

func checkAreEqual(value val: String, expected exp: String, message msg: String) {
if exp != val {
print(msg)
}
}

checkAreEqual(value: "cat", expected: "dog", message: "Incorrect input") 

checkAreEqual(expected: "dog", value: "cat", message: "Incorrect input") 

dateFromString("2014-03-14")

convertCellAt(42, 13) 

convertCellAt(column: 42, row: 13) 

## Methods - 方法

Swift是一种面向对象的语言，因此，你写的应用的逻辑在方法中而不是在全局函数中。方法是与类型（如类，结构，枚举）相关联的一种特殊的函数。在本节中，你会发现一些在Swift中的一些特殊行为是受Object-C语法的大影响的。

## Instance methods - 实例方法

class Cell: CustomStringConvertible {
private(set) var row = 0
private(set) var column = 0
func move(x: Int, y: Int) {
row += y
column += x }
func moveByX(x: Int) {
column += x
}
func moveByY(y: Int) {
column += y
}
var description: String {
get {
return "Cell [row=\(row), col=\(column)]" }
}
} 

var cell = Cell()
cell.moveByX(4)
print(cell.description) 

Cell [row=0, col=4]

var cell = Cell()
cell.moveByX(4)
cell.move(4, y: 7)
print(cell.description)

Swift方法和函数共享一个相同的内部和外部参数名概念相同。然而，他们的默认行为有点区别。一个函数除非你显示的提供了外部名称，否则所有的参数都无外部名称。但在方法中，第一个参数无外部名字，后续的参数默认使用和内部一样的外部名称。

func move(x: Int, _ y: Int) {
row += y
column += x
} 

func move(x: Int = 0, y: Int = 0) {
row += y
column += x
} 

var cell = Cell()
cell.move(4, y: 7)
cell.move(2)
cell.move()
cell.move(y: 3)
print(cell.description)

## Methods are first-class, too - 方法也是一个优秀的类

var cell = Cell() var instanceFunc = cell.moveByY
instanceFunc(34)
print(cell.description) 

Cell [row=0, col=34]

var cell = Cell()
var moveFunc = Cell.moveByY
moveFunc(cell)(34)
print(cell.description)

## Closure expressions as anonymous functions - 闭包函数就像一个匿名函数

func sort(isOrderedBefore: (T, T) -> Bool) -> [T]
（Swift3.0已修改，自行在xcode中查看）

let animals = ["fish", "cat", "chicken", "dog"]
func isBefore(one: String, two: String) -> Bool {
return one > two
}
let sortedStrings = animals.sort(isBefore)
print(sortedStrings) 

[fish, dog, chicken, cat] 

one > two

let animals = ["fish", "cat", "chicken", "dog"]
let sortedStrings = animals.sort({ (one: String, two: String) -> Bool in
return one > two
})
print(sortedStrings) 

let sortedStrings = animals.sort({ (one, two) -> Bool in return one > two
}) 

let sortedStrings = animals.sort({
(one, two) -> Bool in
one > two
}) 

let sortedStrings = animals.sort({
(one, two) in
one > two })

let sortedStrings = animals.sort({
one, two in
one > two })

let sortedStrings = animals.sort({ $0 >$1 }) 

let sortedStrings = animals.sort { $0 >$1 } 

let sortedStrings = animals.sort(>) 

var isBefore = {
(one: String, two: String) -> Bool in  return one > two
}

let sortedStrings = animals.sort(isBefore) 

var isBefore = { (one, two) -> Bool in
return one > two
}
let sortedStrings = animals.sort(isBefore)

## Capturing values - 捕捉值

typealias StateMachineType = () -> Int 

typealias 定义了一个叫StateMachineType的函数类型。这个函数每次调用都返回一个Int。状态用intergers来表示，在每个调用中状态都在一个周期里循环。如，一个状态机有三个状态周期：
0, 1, 2, 0, 1, 2, 0, 1, 2, …

func makeStateMachine(maxState: Int) -> StateMachineType {
return {
currentState+=1
if currentState > maxState {
currentState = 0
}
return currentState
}
} 

let tristate = makeStateMachine(2)
print(tristate())
print(tristate())
print(tristate())
print(tristate())
print(tristate()) 

1
2
0
1
2

let bistate = makeStateMachine(1)
print(bistate());
print(bistate());
print(bistate());
print(bistate()); 

1
0
1
0

func makeStateMachine(maxState: Int) -> StateMachineType {
var currentState: Int = 0   return {
currentState+=1     if currentState > maxState {
currentState = 0
}
return currentState
}
} 

makeStateMachine的第一行定义了一个本地变量currentState，用来保存在当前结构中的状态值。第二行返回一个状态机本身状态的闭合表达式。这一行你省略了闭合表达式的结构（）->Int,因为编译器能够从这种封闭的函数中推断出需要的类型。类型推断是非常聪明的。完整写法如下：

currentState是makeStateMachine中的本地变量，你希望这个函数在返回时即注销。

let tristate = makeStateMachine(2) // currentState

print(tristate()) 

## Memory leaks and capture lists - 内存泄漏和捕获列表

Swift的playground不是一个用来了解内存管理的好地方。在playground的代码是反复运行的，所以，对象的释放不能预测。在这最后一小节，你需要创建一个完整的app。

class Person {
let name: String
private var actionClosure: (() -> ())!
init(name: String) {
self.name = name
actionClosure = {               println("I am \(self.name)")
}
}
func performAction() {
actionClosure()
}
deinit {
print("\(name) is being deinitialized")
}
} 

Person类非常简单，有一个不变的常数属性name，通过初始化设置。还有一个deinit在这个类被销毁时打印一条消息。

override func viewDidLoad() {

let person = Person(name: "bob")
person.performAction()
}

I am bob

ViewController有个对本地常量Person实例的引用。Person有个加name常量属性的引用，有个被分配为私有的闭包函数actionClosure的引用。最后，这个闭包函数内部使用替换字符串的地方使用了self，造成了这个闭包函数对Person的引用。

Swift用的是自动引用计算。每次使用这个对象时都会增加一个对象引用的计数，当一个对象保留的计数为0时，这个对象立即被销毁。这解决了需要停止应用主线程来收集“垃圾”，但是你却需要在使用代码时避免出现循环引用。

__weak typeof(self)weakSelf = self;
[self.context performBlock:^{
__strong typeof(weakSelf)strongSelf = weakSelf;
// do something with strongSelf
}]; 

actionClosure = {
[unowned self] () -> () in
print("I am \(self.name)")
} 

I am bob
bob is being deinitialized

## Where to go from here? - 接着干什么？

0
0

* 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场
个人资料
• 访问：1927次
• 积分：145
• 等级：
• 排名：千里之外
• 原创：4篇
• 转载：1篇
• 译文：9篇
• 评论：0条
文章存档
评论排行