swift专题Swift基础

Swift5 函数与闭包

2020-09-12  本文已影响0人  一粒咸瓜子

函数

是一种特殊的闭包

// 无参无返回值的三种写法
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 语境:

循环引用

方法一:[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()
    }
}
上一篇 下一篇

猜你喜欢

热点阅读