一、
一个Bolock示例,注意,定义block属性的时候,应该是copy,而不是strong,事关栈内存(stack).
#import "BlockTester.h"
// 4: Typedefing blocks
typedef void (^MyBlockType)(id, NSUInteger, BOOL *);
@interface BlockTester ()
//@property (nonatomic, copy) void (^)(id, NSUInteger, BOOL *) block;
@property (nonatomic, copy) MyBlockType block;
@end
@implementation BlockTester {
int _gameCount;
}
- (void)runTests {
// 1: Declaring and calling a block
void (^MyBlock)(id, NSUInteger, BOOL*) = ^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"Video game: %@", (NSString *)obj);
};
MyBlock(@"Path of Exile", 0, NO);
// 2: Passing a block to a method
NSArray *videoGames = @[@"Fallout 2", @"Deus Ex", @"Final Fantasy IV"];
[videoGames enumerateObjectsUsingBlock:MyBlock];
// 2: Inline form
[videoGames enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"Video game: %@", (NSString *)obj);
}];
// Stop
// 3: Calling a method with a block as a parameter
[self doSomethingWithBlock:MyBlock];
// Stop 5: Accessing local variables
NSString *favoriteGame = @"Fallout 2";
[videoGames enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *game = (NSString *)obj;
if ([game isEqualToString:favoriteGame]) {
NSLog(@"w00t, %@ is my favorite game!", (NSString *)obj);
} else {
NSLog(@"Video game: %@", (NSString *)obj);
}
}];
// 6: __block variables
__block int countOfGames = 0;
[videoGames enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"Count of games: %d", countOfGames);
countOfGames++;
}];
NSLog(@"Final Count of games: %d", countOfGames);
// // Stop 7: Retain count
// //__weak BlockTester *weakSelf = self;
// [self doSomethingWithBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// [self logDone];
// }];
}
- (void)logDone {
NSLog(@"Done!");
}
//- (void)doSomethingWithBlock:(void (^)(id, NSUInteger, BOOL *))block {
- (void)doSomethingWithBlock:(MyBlockType)block {
self.block = block;
[self performSelector:@selector(afterOneSecond) withObject:self afterDelay:1.0];
}
- (void)afterOneSecond {
_block(@"The Legend of Zelda", 0, NO);
}
- (void)dealloc {
NSLog(@"BlockTester deallocated!");
}
@end
二、block 结构体信息详解
struct __block_impl
- // __block_impl 是 block 实现的结构体
- struct __block_impl
- {
- void *isa;
- int Flags;
- int Reserved;
- void *FuncPtr;
- };
- isa
- 指向实例对象,表明 block 本身也是一个 Objective-C 对象。block 的三种类型:_NSConcreteStackBlock、_NSConcreteGlobalBlock、_NSConcreteMallocBlock,即当代码执行时,isa 有三种值
- impl.isa = &_NSConcreteStackBlock;
impl.isa = &_NSConcreteMallocBlock;
impl.isa = &_NSConcreteGlobalBlock;
- Flags
- 按位承载 block 的附加信息;
- Reserved
- 保留变量;
- FuncPtr
- 函数指针,指向 Block 要执行的函数,即{ printf("Block\n") };
三、
在 block 内获取了一个外部的局部变量,可以读取,但无法进行写入的修改操作。在 C 语言中有三种类型的变量,可在 block 内进行读写操作
全局变量
全局静态变量
静态变量
全局变量 和 全局静态变量 由于作用域在全局,所以在 block 内访问和读写这两类变量和普通函数没什么区别,而 静态变量 作用域在 block 之外,是怎么对它进行读写呢?通过 clang 工具,我们发现原来 静态变量 是通过指针传递,将变量传递到 block 内,所以可以修改变量值。而上篇文章中的外部变量是通过值传递,自然没法对获取到的外部变量进行修改。由此,可以给我们一个启示,当我们需要修改外部变量时,是不是也可以像 静态变量 这样通过指针来修改外部变量的值呢?
Apple 早就为我们准备了这么一个东西 —— “__block”
__block intValue 翻译后变成了 __Block_byref_intValue_0 结构体指针变量 intValue,通过指针传递到 block 内,这与前面说的 静态变量 的指针传递是一致的
__Block_byref_intValue_0 这个结构体需特别注意下
// 存储 __block 外部变量的结构体
struct __Block_byref_intValue_0
{
void *__isa; // 对象指针
__Block_byref_intValue_0 *__forwarding; // 指向自己的指针
int __flags; // 标志位变量
int __size; // 结构体大小
int intValue; // 外部变量
};
_NSConcreteGlobalBlock
1、当 block 字面量写在全局作用域时,即为 global block;
2、当 block 字面量不获取任何外部变量时,即为 global block;
除了上述描述的两种情况,其他形式创建的 block 均为 stack block。
参考: