一、block内局部变量无法修改,但为什么可以添加数组?
[cpp]
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@"a",@"b",@"abc",nil];
NSMutableArray *mArrayCount = [NSMutableArray arrayWithCapacity:1];
[mArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock: ^(id obj,NSUInteger idx, BOOL *stop){
[mArrayCount addObject:[NSNumber numberWithInt:[obj length]]];
}];
OC中数组等对象,是一个指针
数组添加/删除对象,指针本身并没有变化
因此,除非在block里对数组进行赋值,否则任何操作都是可行的。
下面总结下,block下变量的访问权限:
相同作用域下,局部变量在block内是只读的
相同作用域下,带__block修饰的变量,在block内是可读写的
静态变量和全局变量在block内是可读写的。
当block内使用了局部变量时,block会在栈上保存一份局部变量(block都是存储在栈上的),保存的变量在block里是一个常量,所以不能修改。
若是OC中的对象,blcok会retain,等执行完毕后再release。
如果有带__block的变量,那么block就可以对此变量进行修改。由此可见,带__block的变量不是线程安全的。iOS中,我们经常通过设置request的completionBlock来简化代码时,就需要注意到这一点。
[cpp]
typedef void (^TestBlock) (void);
int val = 20;
TestBlock block1 = ^{ NSLog (@"%d", val); };
val = 50;
TestBlock block2 = ^{ NSLog (@"%d", val); };
val = 5;
TestBlock block3 = ^{ NSLog (@"%d", val); };
block1();
block2();
block3();
//output: 20 50 5
//例如:(无ARC)
//__block id safeSelf = self;
//(有ARC)
//__weak id safeSelf = self; //ios 5
// __unsafe_unretained id safeSelf = self; //ios 4
二,block 注意事项
1,block 在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在 block 块内使用该只读拷贝。
如下代码:
[cpp]
- (void)testAccessVariable
{
NSInteger outsideVariable = 10;
//__block NSInteger outsideVariable = 10;
NSMutableArray * outsideArray = [[NSMutableArray alloc] init];
void (^blockObject)(void) = ^(void){
NSInteger insideVariable = 20;
KSLog(@" > member variable = %d", self.memberVariable);
KSLog(@" > outside variable = %d", outsideVariable);
KSLog(@" > inside variable = %d", insideVariable);
[outsideArray addObject:@"AddedInsideBlock"];
};
outsideVariable = 30;
self.memberVariable = 30;
blockObject();
KSLog(@" > %d items in outsideArray", [outsideArray count]);
}
输出结果为:
> member variable = 30
> outside variable = 10
> inside variable = 20
> 1 items in outsideArray
注意到没?outside 变量的输出值为10,虽然outside变量在定义 block 之后在定义 block 所在的方法 testAccessVariable 中被修改为 20 了。这里的规则就是:blockObject 在实现时会对 outside 变量进行只读拷贝,在 block 块内使用该只读拷贝。因此这里输出的是拷贝时的变量值 10。如果,我们想要让 blockObject 修改或同步使用 outside 变量就需要用 __block 来修饰 outside 变量。
__block NSInteger outsideVariable = 10;
注意:
a),在上面的 block 中,我们往 outsideArray 数组中添加了值,但并未修改 outsideArray 自身,这是允许的,因为拷贝的是 outsideArray 自身。
b),对于 static 变量,全局变量,在 block 中是有读写权限的,因为在 block 的内部实现中,拷贝的是指向这些变量的指针。
c), __block 变量的内部实现要复杂许多,__block 变量其实是一个结构体对象,拷贝的是指向该结构体对象的指针。
2,非内联(inline) block 不能直接访问 self,只能通过将 self 当作参数传递到 block 中才能使用,并且此时的 self 只能通过 setter 或 getter 方法访问其属性,不能使用句点式方法。但内联 block 不受此限制。
[cpp]
typedef NSString* (^IntToStringConverter)(id self, NSInteger paramInteger);
- (NSString *) convertIntToString:(NSInteger)paramInteger
usingBlockObject:(IntToStringConverter)paramBlockObject
{
return paramBlockObject(self, paramInteger);
}
typedef NSString* (^IntToStringInlineConverter)(NSInteger paramInteger);
- (NSString *) convertIntToStringInline:(NSInteger)paramInteger
usingBlockObject:(IntToStringInlineConverter)paramBlockObject
{
return paramBlockObject(paramInteger);
}
IntToStringConverter independentBlockObject = ^(id self, NSInteger paramInteger) {
KSLog(@" >> self %@, memberVariable %d", self, [self memberVariable]);
NSString *result = [NSString stringWithFormat:@"%d", paramInteger];
KSLog(@" >> independentBlockObject %@", result);
return result;
};
- (void)testAccessSelf
{
// Independent
//
[self convertIntToString:20 usingBlockObject:independentBlockObject];
// Inline
//
IntToStringInlineConverter inlineBlockObject = ^(NSInteger paramInteger) {
KSLog(@" >> self %@, memberVariable %
补充:移动开发 , IOS ,