Swift3.0 -- 闭包的循环引用与OC的对比

时间:2023-01-31 18:46:48

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