Block的测试
//输出10 int x = 10; void(^function)(void) = ^(void) { printf("-----> %d",x); }; x = 12; function();
//输出12 int __block x = 10; void(^function)(void) = ^(void) { printf("-----> %d",x); }; x = 12; function();
上面两个换成NSString一样是这种情况,带__block才会输出后面配置的新值。
//输出ab int __block x = 10; NSMutableString *y = [NSMutableString stringWithString:@"a"]; void(^function)(void) = ^(void) { printf("-----> %d\n",x); printf("++++>%s",[y UTF8String]); }; x = 12; [y appendString:@"b"]; function();
可变对象没有问题
//正常输出 const char * text = "hello"; void(^function)(void) = ^(void) { printf("-----> %d\n",x); printf("++++>%s",[y UTF8String]); [items addObject:@(10)]; printf("%c",text[2]); };
//数组没有实现对数组的截获,无法在Block里面使用数组 const char text[] = "hello"; void(^function)(void) = ^(void) { printf("-----> %d\n",x); printf("++++>%s",[y UTF8String]); [items addObject:@(10)]; printf("%c",text[2]); };
@interface YDTestObject : NSObject @property (nonatomic, strong) YDTestObject *otherObject; @property (nonatomic, strong) NSString *name; @property (nonatomic, copy) void (^saveBlock)(void); - (void)doBlock:(void(^)(void))block; - (void)doSaveBlock; @end @interface ViewController () @property (nonatomic, strong) YDTestObject *testObject; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. YDTestObject *testObject = [YDTestObject new]; testObject.name = @"test"; YDTestObject *aObject = [YDTestObject new]; aObject.name = @"a"; YDTestObject *bObject = [YDTestObject new]; bObject.name = @"b"; testObject.otherObject = aObject; aObject.otherObject = bObject; [testObject setSaveBlock:^{ [bObject doBlock:^{ [aObject doBlock:^{ NSLog(@"xxxxxx"); }]; }]; }]; [testObject doSaveBlock]; NSLog(@"测试开始"); } @end @implementation YDTestObject - (void)doBlock:(void (^)(void))block { !block?:block(); } - (void)dealloc { NSLog(@"dealloc: %@",self.name); } - (void)doSaveBlock { !self.saveBlock?:self.saveBlock(); } @end
2020-11-03 19:34:21.953942+0800 justTestUnknow[14796:83939] xxxxxx 2020-11-03 19:34:21.954051+0800 justTestUnknow[14796:83939] 测试开始 2020-11-03 19:34:21.954124+0800 justTestUnknow[14796:83939] dealloc: test 2020-11-03 19:34:21.954185+0800 justTestUnknow[14796:83939] dealloc: a 2020-11-03 19:34:21.954240+0800 justTestUnknow[14796:83939] dealloc: b
上述调用修改为将无法正常释放,aObject和bObject位置互换也是一样无法释放
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. YDTestObject *testObject = [YDTestObject new]; testObject.name = @"test"; YDTestObject *aObject = [YDTestObject new]; aObject.name = @"a"; YDTestObject *bObject = [YDTestObject new]; bObject.name = @"b"; testObject.otherObject = aObject; aObject.otherObject = bObject; [bObject setSaveBlock:^{ [aObject doBlock:^{ [testObject doBlock:^{ NSLog(@"xxxxxx"); }]; }]; }]; [bObject doSaveBlock]; NSLog(@"测试开始"); }
再修改为下面的样子,则是都可以释放
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.testObject = [YDTestObject new]; self.testObject.name = @"test"; YDTestObject *aObject = [YDTestObject new]; aObject.name = @"a"; YDTestObject *bObject = [YDTestObject new]; bObject.name = @"b"; self.testObject.otherObject = aObject; aObject.otherObject = bObject; [aObject setSaveBlock:^{ [bObject doBlock:^{ [self.testObject doBlock:^{ NSLog(@"xxxxxx"); }]; }]; }]; [aObject doSaveBlock]; NSLog(@"测试开始"); self.testObject = nil; }
再把self改成rootObject那么又无法释放内存了
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. YDTestObject *rootObject = [YDTestObject new]; rootObject.name = @"root"; YDTestObject *testObject = [YDTestObject new]; testObject.name = @"test"; YDTestObject *aObject = [YDTestObject new]; aObject.name = @"a"; YDTestObject *bObject = [YDTestObject new]; bObject.name = @"b"; rootObject.otherObject = testObject; testObject.otherObject = aObject; aObject.otherObject = bObject; [aObject setSaveBlock:^{ [bObject doBlock:^{ [rootObject.otherObject doBlock:^{ NSLog(@"xxxxxx"); }]; }]; }]; [aObject doSaveBlock]; NSLog(@"测试开始"); }
再修改一下,又可以正常释放内存了
@interface ViewController () @property (nonatomic, strong) YDTestObject *testObject; @property (nonatomic, strong) YDTestObject *checkObject; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.testObject = [YDTestObject new]; self.testObject.name = @"test"; self.checkObject = [YDTestObject new]; self.checkObject.name = @"a"; YDTestObject *bObject = [YDTestObject new]; bObject.name = @"b"; self.testObject.otherObject = self.checkObject; self.checkObject.otherObject = bObject; [self.checkObject setSaveBlock:^{ [bObject doBlock:^{ [self.testObject doBlock:^{ NSLog(@"xxxxxx"); }]; }]; }]; [self.checkObject doSaveBlock]; NSLog(@"测试开始"); self.checkObject = nil; self.testObject = nil; } @end
如果上面的不写上
self.checkObject = nil;
那么就是只有testObject得到释放了
再改进一下,test和a都释放了,但是b却无法释放
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self testFunction]; [self.checkObject doBlock:^{ NSLog(@"%@",self.checkObject); }]; [self.checkObject setSaveBlock:^{ [self.testObject doBlock:^{ [self.checkObject.otherObject doBlock:^{ NSLog(@"xxxxxx"); }]; }]; }]; [self.checkObject doSaveBlock]; NSLog(@"测试开始"); self.checkObject = nil; self.testObject = nil; } - (void)testFunction { self.testObject = [YDTestObject new]; self.testObject.name = @"test"; self.checkObject = [YDTestObject new]; self.checkObject.name = @"a"; self.testObject.otherObject = self.checkObject; YDTestObject *bObject = [YDTestObject new]; bObject.name = @"b"; self.checkObject.otherObject = bObject; [self.checkObject setSaveBlock:^{ NSLog(@"%@",self.checkObject); }]; [bObject setSaveBlock:^{ NSLog(@"%@",bObject); }]; }
参照上面引入rootObject,导致循环引用的情况,打破它的循环引用
- (void)test2 { YDTestObject *rootObject = [YDTestObject new]; rootObject.name = @"root"; YDTestObject *testObject = [YDTestObject new]; testObject.name = @"test"; YDTestObject *aObject = [YDTestObject new]; aObject.name = @"a"; YDTestObject *bObject = [YDTestObject new]; bObject.name = @"b"; rootObject.otherObject = testObject; testObject.otherObject = aObject; aObject.otherObject = bObject; [aObject setSaveBlock:^{ [bObject doBlock:^{ [rootObject.otherObject doBlock:^{ NSLog(@"xxxxxx"); }]; }]; }]; [aObject doSaveBlock]; NSLog(@"测试开始"); //方案一 rootObject.otherObject = nil; //方案二 // testObject.otherObject = nil;
//方案三
// aObject.saveBlock = nil; }
解决办法:
aObject引用了saveBlock,saveBlock引用了bObject和rootObject,rootObject引用了testObject
循环引用链是 aObject、aObject.saveBlock、rootObject、testObject、aObject
打破循环引用,断其中一个链接即可,对应上述三个方案
对比与其最相似的self.testObject
起初循环引用链为 aObject、aObject.saveBlock、self、self.testObject、aObject
最后一句self.testObject = nil 相当与将 self 和 self.testObject关联打破,破除了循环引用