块和函数类似,只是直接定义在另一个函数里,和定义它的函数共享同一个范围里的东西。用“^”来表示。
NSArray *array = @[@0, @1, @2, @3, @4, @5];
__block NSInteger count = 0;
[array enumerateObjectUsingBlock:^(NSNumber *number, NSUInteger idx, BOOL *stop){
if ([number compare:@2] == NSOrderedAscending) {
count++;
}
}];
传递给enumerateObjectUsingBlock的块事先并没有赋值给局部变量,而是直接内联在函数调用里。
如果快所捕获的变量是对象类型,那么就会自动保留它。系统释放这个块的时候,也会将其一并释放。块本身也有引用计数。
如果将块定义在OC类中的实例方法中,可以使用self变量。块总能修改实例变量,在声明的时候无需加上__block。如果通过读取或写入操作捕获了实例变量,也会把self获取了,因为实例变量是和self关联在一起的。
定义块的时候,其所占的内存区域是分配在栈中的。块只在定义它那个范围里有效。
可以给块对象发送copy消息,把块从栈拷贝到堆。块就可以在定义它的范围外使用了。
只需要给两个block加上copy方法,就可以变得安全。
void (^block)() = ^{
NSLog(@"This is a block");
};
总结:
1.块是C、C++、OC中的词法闭包。
2.块可以接收参数,也可以返回值。
3.块可以分配在栈或者堆上,也可以是全局的。分配在栈上的块可以拷贝到堆里,这样就和对象一样具备引用计数了。
^{
//block
};
块和int,float或其他对象一样,可以作为一个值赋给变量并使用。块类型的语法和函数指针类似。
void (^someBlock)() = ^{
//block
};
块类型的语法结构:
return_type (^block_name)(parameters)
接收两个int做参数,并返回int值:
int (^addBlock)(int a,int b) = ^(int a, int b) {
return a + b;
};
定义好后,可以使用:
int add = addBlock(2, 5);
block的好处是,在它的声明范围里,所有的变量都可以被捕获。那个范围里的变量,在块里依然可以使用
int additional = 5;
int (^addBlock)(int a, int b) = ^(int a, int b){
return a + b + additional;
};
int add = addBlock(2, 5);
默认情况下,块所捕获的变量是不可以在块中修改的,如果改变additional的值,编译器就会报错。变量声明的时候可以加上__block修饰符,就能在块中修改变量了。
NSArray *array = @[@0, @1, @2, @3, @4, @5];
__block NSInteger count = 0;
[array enumerateObjectUsingBlock:^(NSNumber *number, NSUInteger idx, BOOL *stop){
if ([number compare:@2] == NSOrderedAscending) {
count++;
}
}];
传递给enumerateObjectUsingBlock的块事先并没有赋值给局部变量,而是直接内联在函数调用里。
如果快所捕获的变量是对象类型,那么就会自动保留它。系统释放这个块的时候,也会将其一并释放。块本身也有引用计数。
如果将块定义在OC类中的实例方法中,可以使用self变量。块总能修改实例变量,在声明的时候无需加上__block。如果通过读取或写入操作捕获了实例变量,也会把self获取了,因为实例变量是和self关联在一起的。
@interface EOCClass
-(void)anInstanceMethod {
void (^someBlock)() = ^{
_anInstanceVariable = @"Something";
NSLog(@"_anInstanceVariable = %@", _anInstanceVariable);
};
}
@end
如果某个EOCClass实例正在执行anInstanceMethod方法,self变量就指向此实例。由于块里没有明确使用self变量,所以很容易疏忽。直接访问实例变量和通过self访问是等效的:
self->_anInstanceVariable = @"Something";
self.anInstanceVariable = @"Something";
self也是一个对象,块在捕获它的时候也会将其保留。如果self那个对象同时也保留了块,就会形成保留环。
定义块的时候,其所占的内存区域是分配在栈中的。块只在定义它那个范围里有效。
void (^block)();
if(/...../) {
block = ^{
NSLog(@"Block A");
}
} else {
block = ^{
NSLog(@"Block B");
}
}
block();
定义在if 和 else 的语句中两个block都分配在栈中。编译器会给每个块分配好栈内存,等离开相应范围后,分配给块的内存可能被覆写掉。两个块只能在对应的if else 语句范围内有效。这样写可以编译,运行时而有效时而错误。没覆写,程序正常运行,已覆写,程序崩溃。
可以给块对象发送copy消息,把块从栈拷贝到堆。块就可以在定义它的范围外使用了。
只需要给两个block加上copy方法,就可以变得安全。
void (^block)();
if(/...../) {
[block = ^{
NSLog(@"Block A");
} copy];
} else {
[block = ^{
NSLog(@"Block B");
} copy];
}
block();
全局块,这种块不会不捉任何状态,块所使用的整个内存区域,在编译器已经完全确定了。全局块可以声明在全局内存里,全局块的拷贝是个空操作,因为全局块不可能被系统回收,这种块相当于单例。
void (^block)() = ^{
NSLog(@"This is a block");
};
总结:
1.块是C、C++、OC中的词法闭包。
2.块可以接收参数,也可以返回值。
3.块可以分配在栈或者堆上,也可以是全局的。分配在栈上的块可以拷贝到堆里,这样就和对象一样具备引用计数了。