在block内如何修改block外部变量?
1、Block中不允许修改外部变量的值。这里所说的外部变量的值,指的是栈中指针的内存地址。__block修饰之后,立马将“外部变量在栈中的内存地址放到堆中”,如果不做特殊修改就一直在堆中,进而做到在block内部修改外部变量。
2、大小比较:堆地址要小于栈地址。iOS中一个进程的栈区内存只有1M,Mac也只有8M。
3、这里的a已经由基本数据类型,变成了对象类型。block会对对象类型的指针进行copy,copy到堆中,但并不会改变该指针所指向的堆中的地址
__block int a = 5;
NSLog(@"定义前:%p",&a); // 1、栈中
void (^foo)(void) = ^{
a = 6;
NSLog(@"block内部:%p",&a); //3、堆中
};
NSLog(@"定义后:%p",&a);//2、堆中
foo();
定义前:0x16fda86f8
定义后:0x155b22fc8
block内部: 0x155b22fc8
NSMutableString *a = [NSMutableString stringWithString:@"Tom"];
NSLog(@"\n 定以前:------------------------------------\n\
a指向的堆中内存对象的地址:%p;a在栈中的指针地址:%p", a, &a);
void (^foo)(void) = ^{
a.string = @"Jerry";
NSLog(@"\n block内部:------------------------------------\n\
a指向的堆中内存对象的地址:%p;a在栈中的指针地址:%p", a, &a);
// a = [NSMutableString stringWithString:@"William"];
};
foo();
NSLog(@"\n 定以后:------------------------------------\n\
a指向的堆中内存对象的地址:%p;a在栈中的指针地址:%p", a, &a);

使用系统的某些block api(如UIView的block版本写动画时),是否也考虑引用循环问题?
1、统的某些block api中,UIView的block版本写动画时不需要考虑,所谓“引用循环”是指双向的强引用,所以那些“单向的强引用”(block 强引用 self )没有问题,比如这些:
[UIView animateWithDuration:duration animations:^{ [self.superview layoutIfNeeded]; }];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.someProperty = xyz; }];
[[NSNotificationCenter defaultCenter] addObserverForName:@"someNotification"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * notification) {
self.someProperty = xyz; }];
这些情况不需要考虑“引用循环”。
但如果你使用一些参数中可能含有 ivar 的系统 api ,如 GCD 、NSNotificationCenter就要小心一点:比如GCD 内部如果引用了 self,而且 GCD 的其他参数是 ivar,则要考虑到循环引用:
__weak __typeof__(self) weakSelf = self;
dispatch_group_async(_operationsGroup, _operationsQueue, ^
{
__typeof__(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf doSomethingElse];
} );
__weak __typeof__(self) weakSelf = self;
_observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
__typeof__(self) strongSelf = weakSelf;
[strongSelf dismissModalViewControllerAnimated:YES];
}];
self –> _observer –> block –> self 显然这也是一个循环引用。
检测代码中是否存在循环引用问题,可使用 Facebook 开源的一个检测工具 FBRetainCycleDetector 。