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;
};
  1.  __block_impl个人理解为block的基类,类似NSObject。
  2. __main_block_impl_0:可以理解为block变量。一个block对象包含一个__block_impl,一个描述__main_block_desc_0。
  3. __main_block_func_0:block代码块的实现。
  4. __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什么时候释放。

希望明白的同学不吝赐教。

原文地址:https://www.cnblogs.com/yzvictory/p/5714135.html