閉包的循環引用 與 解決(三種方法)html
//******************************************************web
//******************************************************安全
//******************************************************網絡
閉包的循環引用閉包
import UIKit異步
class ViewController: UIViewController {async
// 定義完成回調屬性ide
// 閉包的返回值可選spa
// var finishedCallBack: ()->()?線程
// 閉包屬性可選
var finishedCallBack: ((html: String)->())?
override func viewDidLoad() {
super.viewDidLoad()
loadData { (html) -> () in
print(html)
print(self.view)
}
}
deinit {
print("控制器 88")
}
// 閉包應用場景:異步操做完成後,經過閉包的參數傳遞網絡請求結果
func loadData(finished: (html: String) -> ()) {
// 1. 記錄完成回調
finishedCallBack = finished
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("模擬異步加載數據")
// 主線程回調
dispatch_async(dispatch_get_main_queue(), { () -> Void in
print("主線程回調")
// 若是回調不能在當前方法當即執行,能夠經過屬性記錄,在須要的時候用執行
// finished(html: "<html>")
self.finishedCallBack?(html: "hahah")
})
}
}
}
//******************************************************
//******************************************************
//******************************************************
解決辦法
import UIKit
class ViewController: UIViewController {
// 定義完成回調屬性
// 閉包的返回值可選
// var finishedCallBack: ()->()?
// 閉包屬性可選
var finishedCallBack: ((html: String)->())?
override func viewDidLoad() {
super.viewDidLoad()
// 方法三:Swift 的方法2
// [unowned self] 表示閉包中的 self 都是 assign -> 若是 self 被釋放,閉包中的 self 的地址不會修改
// 與__unsafe_unretained相似,若是 self 被釋放,一樣會出現野指針
loadData { [unowned self] (html) -> () in
print(html)
// self? 表示對象一旦被釋放,再也不訪問其屬性或者方法
print(self.view)
}
}
func demo2() { //推薦使用
// 方法二:Swift 的方法1
// [weak self] 表示閉包中的 self 都是 弱引用
// 與 __weak 相似,若是 self 被釋放,什麼也不作,更安全
loadData { [weak self] (html) -> () in
print(html)
// self? 表示對象一旦被釋放,再也不訪問其屬性或者方法
print(self?.view)
}
}
// 方法一:OC 的傳統方法
func demo1() {
// weak 屬性在運行時可能會被改變 -> 執行對象一旦被釋放,變成 nil
// weak 屬性不能是 let
weak var weakSelf = self
loadData { (html) -> () in
print(html)
// 閉包中,必定要使用 self.
// weakSelf? 表示對象一旦被釋放,再也不訪問其屬性或者方法
print(weakSelf?.view)
}
}
deinit {
print("控制器 88")
}
// 閉包應用場景:異步操做完成後,經過閉包的參數傳遞網絡請求結果
func loadData(finished: (html: String) -> ()) {
// 1. 記錄完成回調
finishedCallBack = finished
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("模擬異步加載數據")
// 主線程回調
dispatch_async(dispatch_get_main_queue(), { () -> Void in
print("主線程回調")
// 若是回調不能在當前方法當即執行,能夠經過屬性記錄,在須要的時候用執行
// finished(html: "<html>")
self.finishedCallBack?(html: "hahah")
})
}
}
}
Swift
[unowned self]
self
不是可選項,若是self已經被釋放,則出現野指針訪問
[weak self]
self
是可選項,若是self已經被釋放,則爲nil
[weak self]
[unowned self]
Objc
__unsafe_unretained typeof(self) weakSelf;
若是self
已經被釋放,則出現野指針訪問
__weak typeof(self) weakSelf;
若是self
已經被釋放,則爲nil