$ 问题抛出来
1.所有自定义方法的
block
都需要__weak
吗?
2.凡是,block
内带self
的都需要__weak
吗?
3.凡是, 系统方法中的block
, 都不需要__weak
吗?
看看上述问题的反问语气, 相必语文过关的同学们都知道答案,一看就是 No No No ~
-> 😄 恭喜你~ right !
$ but why ?
至于原因 👇
想必大伙都知道, 互相strong
持有成了一个环 , 然后就无法释放了~
$ block 常见场景(暂时想到的一些情况, 后续想到继续补充)
first, code准备:
👇 一个子View -- TestOneView, 创建各种参数为block的方法
// TestOneView.h
#import <UIKit/UIKit.h>
typedef void(^ZYOneBlock1)();
typedef void(^ZYOneBlock2)();
@interface TestOneView : UIView
// copy修饰
@property (nonatomic, copy) ZYOneBlock1 oneBlock;
// weak修饰
@property (nonatomic, weak) ZYOneBlock1 weak_oneBlock;
// 持有 传入的block , 但是 weak
- (void)testWeakBlock:(ZYOneBlock1) block;
// 不持有 传入的block , 在method中直接执行掉
- (void)testBlock2WithBlock:(ZYOneBlock2) secondblock;
@end
// TestOneView.m
#import "TestOneView.h"
@implementation TestOneView
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
// 持有 传入的block , strong
-(void)setOneBlock:(ZYOneBlock1)oneBlock{
_oneBlock = oneBlock;
_oneBlock();
}
// 持有 传入的block , 但是 weak
- (void)testWeakBlock:(ZYOneBlock1) block;
{
self.weak_oneBlock = block;
}
// 不持有 传入的block , 在method中直接执行掉
- (void)testBlock2WithBlock:(ZYOneBlock2) secondblock;
{
secondblock();
}
// 通过dealloc 检测能否释放
-(void)dealloc{
NSLog(@"%s",__func__);
}
@end
go on ~ , code一个被push的VC -- TestOneViewController , 即是 block纵横所在的江湖
😏😏😏 block 出场 😏😏😏
-
<1> A 操作 B的bloc
(1).传给子View的block被子view 👉
strong
持有 , block块中使用了_ivar(成员变量) 、strong property , 处理方式如下:- (void)testStrongBlock_1{ [self.view addSubview: self.oneView]; __weak typeof(self) weakSelf = self; self.oneView.oneBlock = ^{ __strong typeof(weakSelf) strongSelf = weakSelf; strongSelf->_intType = 11; strongSelf.pArray = @[@(11)]; }; }
(2).传入的block块中 含有本类的实例方法
- (void)testMethod_StrongBlock_1{ [self.view addSubview: self.oneView]; __weak typeof(self) weakSelf = self; self.oneView.oneBlock = ^{ __strong typeof(weakSelf) strongSelf = weakSelf; // method [strongSelf containSelfMethod]; }; } - (void)containSelfMethod{ _intType = 1010; self.pArray = @[@(2020)]; }
(3).传给子view的block 被子view 👉
weak
持有, 在方法内被执行完。无需weakSelf- (void)testWeakBlock_1{ [self.view addSubview: self.oneView]; [self.oneView testWeakBlock:^{ _intType = 111; self.pArray = @[@(1)]; }]; }
(4).传给子view的block ❌不 被子view 持有, 直接执行掉。
无需weakSelf- (void)testParamBlock_2{ [self.view addSubview: self.oneView]; [self.oneView testBlock2WithBlock:^{ _intType = 22; self.pArray = @[@(1)]; }]; }
-
<2> A 操作 A的block
(a).block作参数, ❌不 被持有
- (void)testParam_SelfBlock_1{ [self testParam_SelfBlcokWith:^(NSArray * arr) { self.pArray = arr; NSLog(@"%s",__func__); }]; } - (void)testParam_SelfBlcokWith:(MyBlockOne)myBlock{ NSArray * arr = @[@"myblock1"]; myBlock(arr); }
(b).block作参数, 👉被持有
- (void)testCopy_SelfBlock_1{ __weak typeof(self) weakSelf = self; [self testCopy_SelfBlcokWith:^(NSArray * arr) { __strong typeof(weakSelf) strongSelf = weakSelf; strongSelf.pArray = arr; NSLog(@"%s",__func__); }]; } - (void)testCopy_SelfBlcokWith:(MyBlockOne)myBlock{ self.myBlock1 = myBlock; NSArray * arr = @[@"myblock1"]; NSLog(@"%s",__func__); sleep(1); NSLog(@"%s",__func__); self.myBlock1(arr); }
-
<3> GCD的block(系统的)
无需weakSelf。注意: GCD延时block, 会使VC pop后延迟释放- (void)didMoveToParentViewController:(UIViewController *)parent{ [self.oneView removeFromSuperview]; NSLog(@"%s , %@",__func__ ,self); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"%s , %@",__func__ ,self); [self testBackTimerAfter]; // 点击pop 时,会延迟2s dealloc }); } - (void)testBackTimerAfter{ [self.oneView testWeakBlock:^{ NSLog(@"%s , %@",__func__ ,self); }]; __weak typeof(self) weakSelf = self; _oneView.oneBlock = ^{ __strong typeof(weakSelf) strongSelf = weakSelf; NSLog(@"%s , %@",__func__ ,strongSelf); }; }
-
<4> ☺补充☺, 对于NSTimer addTarget: self...
_weak typeof(self) weakSelf = self; _timer = [NSTimer scheduledTimerWithTimeInterval:3.0f target:weakSelf selector:@selector(timerFire:) userInfo:nil repeats:YES];
对于如上解决方式, 是有误的,详解 可参考 👉 解决NSTimer/CADisplayLink的循环引用
超懒人 点击 github demo 下载 调试 。
祝愿有所收获哦 ~ _ ~