简介:本文主要讲:函数的定义,外部参数的用处,无返回类型的三种函数定义方式
闭包的定义,闭包的概念和用法,尾随闭包的写法,解除循环引用的方法
一、函数:
代码实现
- 函数的定义
- 格式
func 函数名(行参列表) -> 返回值 {代码实现}
- 调用
let result = 函数名(值1, 参数2: 值2...)
- 格式
func sum(a: Int, b: Int) -> Int { return a + b } let result = sum(10, b: 20)
- 没有返回值的函数,一共有三种写法
- 省略
- ()
- Void
func demo(str: String) -> Void { print(str) } func demo1(str: String) -> () { print(str) } func demo2(str: String) { print(str) } demo("hello") demo1("hello world") demo2("olleh")
- 外部参数
- 在形参名前再增加一个外部参数名,能够方便调用人员更好地理解函数的语义
- 格式:
func 函数名(外部参数名 形式参数名: 形式参数类型) -> 返回值类型 { // 代码实现 }
- Swift 2.0 中,默认第一个参数名省略
func sum1(num1 a: Int, num2 b: Int) -> Int { return a + b } sum1(num1: 10, num2: 20)
二、闭包:
与 OC 中的 Block 类似,闭包
主要用于异步操作执行完成后的代码回调,网络访问结果以参数的形式传递给调用方
闭包的定义
- 定义一个函数
//: 定义一个 sum 函数
func sum(num1 num1: Int, num2: Int) -> Int { return num1 + num2 } sum(num1: 10, num2: 30) //: 在 Swift 中函数本身就可以当作参数被定义和传递 let mySum = sum let result = mySum(num1: 20, num2: 30)
- 定义一个闭包
- 闭包 = { (行参) -> 返回值 in // 代码实现 }
in
用于区分函数定义和代码实现
//: 闭包 = { (行参) -> 返回值 in // 代码实现 }
let sumFunc = { (num1 x: Int, num2 y: Int) -> Int in return x + y } sumFunc(num1: 10, num2: 20)
- 最简单的闭包,如果没有参数/返回值,则
参数/返回值/in
统统都可以省略- { 代码实现 }
let demoFunc = {
print("hello")
}
基本使用
GCD 异步
- 模拟在后台线程加载数据
func loadData() {
dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in print("耗时操作 \(NSThread .currentThread())") }) }
- 尾随闭包,如果闭包是最后一个参数,可以用以下写法
- 注意上下两段代码,
}
的位置
func loadData() {
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in print("耗时操作 \(NSThread .currentThread())") } }
- 闭包的简写,如果闭包中没有参数和返回值,可以省略
func loadData() {
dispatch_async(dispatch_get_global_queue(0, 0)) { print("耗时操作 \(NSThread .currentThread())") } }
自定义闭包参数,实现主线程回调
- 添加没有参数,没有返回值的闭包
override func viewDidLoad() { super.viewDidLoad() loadData { print("完成回调") } } // MARK: - 自定义闭包参数 func loadData(finished: ()->()) { dispatch_async(dispatch_get_global_queue(0, 0)) { print("耗时操作 \(NSThread.currentThread())") dispatch_sync(dispatch_get_main_queue()) { print("主线程回调 \(NSThread.currentThread())") // 执行回调 finished() } } }
- 添加回调参数
override func viewDidLoad() { super.viewDidLoad() loadData4 { (html) -> () in print(html) } } /// 加载数据 /// 完成回调 - 传入回调闭包,接收异步执行的结果 func loadData4(finished: (html: String) -> ()) { dispatch_async(dispatch_get_global_queue(0, 0)) { print("加载数据 \(NSThread.currentThread())") dispatch_sync(dispatch_get_main_queue()) { print("完成回调 \(NSThread.currentThread())") finished(html: "<h1>hello world</h1>") } } }
循环引用
- 建立
NetworkTools
对象
class NetworkTools: NSObject {
/// 加载数据 /// /// - parameter finished: 完成回调 func loadData(finished: () -> ()) { print("开始加载数据...") // ... finished() } deinit { print("网络工具 88") } }
- 实例化
NetworkTools
并且加载数据
class ViewController: UIViewController {
var tools: NetworkTools? override func viewDidLoad() { super.viewDidLoad() tools = NetworkTools() tools?.loadData() { print("come here \(self.view)") } } /// 与 OC 中的 dealloc 类似,注意此函数没有() deinit { print("控制器 88") } }
运行不会形成循环引用,因为 loadData 执行完毕后,就会释放对 self 的引用
- 修改
NetworkTools
,定义回调闭包属性
/// 完成回调属性
var finishedCallBack: (()->())?
/// 加载数据
///
/// - parameter finished: 完成回调 func loadData(finished: () -> ()) { self.finishedCallBack = finished print("开始加载数据...") // ... working() } func working() { finishedCallBack?() } deinit { print("网络工具 88") }
运行测试,会出现循环引用
解除循环引用
- 与 OC 类似的方法
/// 类似于 OC 的解除引用
func demo() { weak var weakSelf = self tools?.loadData() { print("\(weakSelf?.view)") } }
- Swift 推荐的方法
loadData { [weak self] in
print("\(self?.view)") }
- 还可以
loadData { [unowned self] in
print("\(self.view)") }
闭包(Block) 的循环引用小结
-
Swift
[weak self]
self
是可选项,如果self已经被释放,则为nil
[unowned self]
self
不是可选项,如果self已经被释放,则出现野指针访问
-
Objc
__weak typeof(self) weakSelf;
- 如果
self
已经被释放,则为nil
- 如果
__unsafe_unretained typeof(self) weakSelf;
- 如果
self
已经被释放,则出现野指针访问
- 如果
Swift 的详细介绍:请点这里