Swift3.0 -- 閉包的迴圈引用與OC的對比
阿新 • • 發佈:2019-01-08
import UIKit class ViewController: UIViewController { var a: (() -> ())? override func viewDidLoad() { super.viewDidLoad() //block 中如果出現 self. 要特別小心! // "迴圈"引用,單方向的引用是不會產生迴圈引用的 // - 只是閉包對self 進行了copy // - 同時需要self對閉包引用 //*******解除迴圈引用 // 方法一:用oc的方法 // 細節1:用var不用let,weak只能修飾var 不能 修飾 let // 'weak' must be a mutable variable, because it may change at runtime // weak可能會在執行時被修改 -> 指向的物件一旦被釋放,會自動設定為nil // weak var weakSelf = self; // loadData { // 細節2 // 解包有兩種方式 // ? 可選解包 如果self已經被釋放,不會向物件傳送 view 的訊息,更安全 // ! 強行解包 如果self已經被釋放,強行解包會導致崩潰 // Expression implicitly coerced from 'UIView?' to Any /* weakSelf?.view 只是單純的傳送訊息,不參與計算 強行解包,因為需要計算,可選項不能直接參與計算 */ // print(weakSelf?.view); // } //方法2 - swift的推薦方法 //[weak self] 表示 () 中的所有 self 都為弱引用 // loadData { [weak self] in // print(self?.view as Any); // } // 方法3 - swift的另一種方法,知道就好,不安全 // [unowned self] 表示 () 中的所有 self 都為assign, 不會強引用,如果物件釋放,指標地址依然存在 // 如果物件釋放, 會出現野指標的現象 loadData { [unowned self] in print(self.view); } } func loadData(bibao: @escaping () -> ()) { // 使用屬性記錄閉包 -> self 對閉包引用 a = bibao; //非同步 DispatchQueue.global().async { print("1111"); Thread.sleep(forTimeInterval: 2); DispatchQueue.main.async(execute: { print("2222"); bibao(); }) } } deinit { print("qqqqq"); } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
與OC的對比
#import "DemoViewController.h" @interface DemoViewController () @property (nonatomic, copy) void (^blockCallBack)(); @end @implementation DemoViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. // //解除方法1:-- __weak // __weak typeof(self) weakSelf = self; // [self loadData:^{ // NSLog(@"%@", weakSelf.view); // }]; //解除方法2:-- __unsafe_unretained //EXC_BAD_ACCESS ,壞記憶體訪問,野指標訪問 // __unsafe_unretained 同樣是assign的引用(MRC中並未有weak) // MRC中,弱引用直接用assign,不會增加引用計數,但是物件一旦被釋放,會出現野指標 // ARC中,__weak相當於一個觀察者,一旦發現物件被釋放,會自動設定為nil,會更加安全。 //weak的效率會差一些 __unsafe_unretained typeof(self) weakSelf = self; [self loadData:^{ NSLog(@"%@", weakSelf.view); }]; } -(void)loadData:(void (^)())block { self.blockCallBack = block; dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"延時操作:%@", [NSThread currentThread]); [NSThread sleepForTimeInterval:2.0]; dispatch_async(dispatch_get_main_queue(), ^{ block(); }); }); } @end