iOS Block原理简析
- Block的语法
Block是iOS闭包的实现方式,能够获取局部变量的匿名函数。
Block的OC声明
返回值类型 (^Block变量名字)(参数列表) = (参数列表){};
例子
int (^add)(int a,int b) = ^(int a, int b) { return a + b; }; int sum = add(1,4); NSLog(@"sum = %d",sum); NSString* (^getFullName)(NSString *first,NSString *last) = ^(NSString *first,NSString *last) { return [NSString stringWithFormat:@"%@%@",first,last]; }; NSString *name = getFullName(@"张",@"三"); NSLog(@"name = %@",name);
- Block使用
保存局部代码块
//声明实现 void (^sayHello)() = ^() { NSLog(@"hello world"); }; //调用 sayHello();
作为一般的数据类型
使用block的时候为了方便,一般都会使用关键字typedef
typedef void (^someOne)(int age,NSString *name); someOne same = ^(int age,NSString *name) { NSLog(@"age = %d.name = %@",age,name); }; same(19,@"same");
//作为参数使用 -(void)getSomeOne:(someOne)some; - (void)getSomeOne:(someOne)some { if (some) { some(20,@"lisi"); } } BlockMode *mode = [[BlockMode alloc]init]; [mode getSomeOne:^(int age, NSString *name) { NSLog(@"age = %d.name = %@",age,name); }];
Block和函数的区别:1.声明方式不一样;2.block可以作为参数或者普通变量使用。
- Block底层实现原理
在终端中cd命令移动到main.m所在的目录,然后使用命令,clang -rewrite-objc main.m,生成一个cpp的源文件。这个源文件的最后是我们main函数的实现。
typedef void (*someOne)(int age,NSString *name); struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static int __main_block_func_0(struct __main_block_impl_0 *__cself, int a, int b) { return a + b; } static struct __main_block_desc_0 { size_t reserved; size_t Block_size; } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)}; int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; int (*add)(int a,int b) = ((int (*)(int, int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)); int sum = ((int (*)(__block_impl *, int, int))((__block_impl *)add)->FuncPtr)((__block_impl *)add, 10, 20); } return 0; }
这里要理解几个结构体。
struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; };
- __block_impl个人理解为block的基类,类似NSObject。
- __main_block_impl_0:可以理解为block变量。一个block对象包含一个__block_impl,一个描述__main_block_desc_0。
- __main_block_func_0:block代码块的实现。
- __main_block_desc_0:block的描述, Block_size;
如果需要在block中修改局部变量,需要使用__block关键字。那么为什么加了这个之后就可以修改呢,继续看源代码。
看看加了__block之后会有什么变化
这就是为什么,加了__block之后,对变量进行修改,就可以。类似函数传参的传值和传引用。
最后有点疑问如下:
__block NSString *name = @"lise"; void (^getName)() = ^() { NSLog(@"name = %@",name); }; name = @"ali"; getName();//假如这个block块永远没有执行,name什么时候释放。
希望明白的同学不吝赐教。