簡介:本文主要講:函數的定義,外部參數的用處,無返回類型的三種函數定義方式 閉包的定義,閉包的概念和用法,尾隨閉包的寫法,解除迴圈引用的方法 一、函數: 代碼實現 函數的定義 格式 func 函數名(行參列表) -> 返回值 {代碼實現} 調用 let result = 函數名(值1, 參數2: 值 ...
簡介:本文主要講:函數的定義,外部參數的用處,無返回類型的三種函數定義方式
閉包的定義,閉包的概念和用法,尾隨閉包的寫法,解除迴圈引用的方法
一、函數:
代碼實現
- 函數的定義
- 格式
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
已經被釋放,則出現野指針訪問
- 如果