函数
是一种特殊的闭包
// 无参无返回值的三种写法
func a() -> Void { ... }
func a() -> () { ... }
func a() { ... } //最简
// 有参数无返回值
func square(a: Int, b: Int) -> Int { return a * b }
// 有参数有返回值
func square(a: Int, b: Int) { ... } //最简
内部函数
在函数体内部定义的函数,调用需在声明后
func result() {
func sum(a: Int, b: Int) -> Int {
return a + b
}
//在内部函数声明的下面调用
print(sum(a: 20, b: 80))
}
外部参数及忽略
提供外部参数能增强函数的可读性,同时也能够让函数在内部使用参数更加简单
忽略外部参数用 “_” 表示
// frist/second表示外部参数,a标识函数的内部参数只能够在函数的内部使用
func sum(first a: Int, second b: Int) -> Int {
return a + b
}
sum(first: 10, second: 20);
// 忽略外部参数 “_”
func sum(_ a: Int, _ b: Int) -> Int {
return a + b
}
sum(10, 20);
函数小技巧
多返回值:元组类型
oc 中使用输出参数实现
使用元组来让一个函数返回多个值。该元组的元素可以用名称或数字来表示。
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
//let statistics: (min: Int, max: Int, sum: Int)
let statistics = calculateStatistics(scores:[5, 3, 100, 3, 9])
//或者print(statistics.2) 该元组的元素可以用名称或数字来表示
print(statistics)
不确定参数
oc 中使用 va_list 等宏实现
参数个数可变:函数可以带有可变个数的参数,这些参数在函数内表现为数组的形式
func nameFunc(names: String...) {
for name in names {
print(name, terminator: " ")
}
}
nameFunc(names: "zhangsan", "lisi", "wangwu")
// Prints "zhangsan lisi wangwu "
闭包
closure:Swift 中的 block
闭包是一个封闭的结构: 闭包的参数,返回值、需要执行的代码片段 都应该在闭包的内部
函数和闭包都是引用类型:无论你将函数或闭包赋值给一个常量还是变量,你实际上都是将常量或变量的值设置为对应函数或闭包的引用
// block
void(^callback)(NSString *) = ^(NSString *str) {
// code
}
// closure
let closure = { (str: String) -> () in
// code
}
写法
一般左边不写,参数类型和返回值类型在闭包内标明即可
- 无参无返回值
// 完整形式 左右都有 标明闭包类型
let closure:() -> () = { () -> () in
print("最简单的闭包完整形式")
}
// 简化:左边不写,右边标明闭包类型,返回值为空时,写()和 Void 一样
let closure = { () -> Void in
print("返回值为空时")
}
// 最简形式
let closure = {
print("最简形式")
}
- 有参无返回值
let closure = { (a: Int, b: Int) in
print("\(a) + \(b) = \(a+b)")
}
- 有参有返回值
let closure = { (a: Int, b: Int) -> (String) in
return "\(a+b)"
}
尾随闭包
当函数的最后一个参数是闭包的时候,函数的参数的 '()' 可提前关闭。
如果函数只有闭包这一个参数, '()' 可以省略,如果闭包类型是无参无返回值,"() -> () in" 也可以省略。
是在调用函数的时候可以省略,而不是声明的时候
bug:如果写出来的闭包函数报错,可以在声明的时候把返回值写上,调用成功后再删除
func loadData(name: String, completed: (Int) -> ()) {
completed((name as NSString).length)
}
loadData(name: "abc") { (count) in
print("name's count = " + "\(count)")
}
//Prints "name's count = 3"
func cFunc(closure: () -> ()) {
closure()
}
cFunc {
// code
}
@escaping
逃逸闭包:当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 @escaping,⽤来指明这个闭包是允许“逃逸”出这个函数的
@escaping:标识该闭包可以逃离当前的“语境”,写在闭包类型声明之前,闭包作为函数的参数是默认不可逃逸的。
@escaping 语境:
-
闭包在 async 需要逃逸、sync 不需要逃逸
-
闭包被引用,需要逃逸。
循环引用
方法一:[weak self] (推荐)
self 是可选项,如果 self 已经被释放,则为 nil
// 类似 OC 中:__weak typeof(self) weakSelf;
// 如果 self 已经被释放,则为 nil
loadData { [weak self] in
print("\(self?.view)")
}
方法二: [unowned self] (不推荐)
self 不是可选项,如果 self 已经被释放,则出现野指针访问
// 类似 OC 中:__unsafe_unretained typeof(self) weakSelf;
// 如果 self 已经被释放,则出现野指针访问
loadData { [unowned self] in
print("\(self.view)")
}
方法三:与 OC 类似
weak var weakSelf = self
loadData() {
print("\(weakSelf?.view)")
}
网络请求试写
func request(urlStr: String, compeletd:@escaping (Bool, Any) -> Void) {
guard let url = URL(string: urlStr) else {
return
}
DispatchQueue.global().async {
URLSession.shared.dataTask(with: url) { (data, _, error) in
if error != nil {
DispatchQueue.main.async {
compeletd(false, error!)
}
} else {
let json = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
DispatchQueue.main.async {
compeletd(true, json!)
}
}
}.resume()
}
}