美文网首页
iOS开发之Block

iOS开发之Block

作者: DB001 | 来源:发表于2020-07-03 15:40 被阅读0次

    block的本质
    • block本质上也是一个OC对象,它内部也有个isa指针。
    • block是封装了函数调用以及函数调用环境OC对象。
    • block的底层结构如右图所示:
    block01.png
    block的变量捕获(capture)
    • 为了保证block内部能够正常访问外部的变量block有个变量捕获机制。

      block02.png
    • 1.局部变量-auto

    {
    auto int age = 10;//auto可以省略
    void(^block)(void)=^{
    
         //age的值捕获进来(capture)
         NSLog(@"age is %d,height is %d",age,height);
    
    };
    
    age = 20;
    
    block();
    }
    
    编译之后的:
    {
    struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr;
    };
    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      int age;//捕获到的值
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    //  age(_age) C++语法  ==>     age = _age;
      }
    };
    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
      
        //变量捕获
        int age = __cself->age; // bound by copy
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_hl_g93_s7nx05zdzh42fv2fp4rw0000gn_T_main_04a8a7_mi_0,age);
    }
    
    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 age = 10;
    void(*block) = &__main_block_impl_0(
                                                __main_block_func_0,
                                                &__main_block_desc_0_DATA,
                                                age);
     age = 20;
    block->FuncPtr(block);
    }
    
    • 2.局部变量-static
      block03.png
    {
    static int height = 10;
    void(^block)(void)=^{
    
         //height的值捕获进来(capture)
         NSLog(@"height is %d",height);
    
    };
    
    height = 20;
    
    block();
    }
    
    编译之后的:
    {
    struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr;
    };
    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      int *height;//捕获到的指针
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_height, int flags=0) : height(_height)  {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    //  age(_age) C++语法  ==>     age = _age;
      }
    };
    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
      
        //变量捕获
        int *height = __cself->height; // bound by copy
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_hl_g93_s7nx05zdzh42fv2fp4rw0000gn_T_main_04a8a7_mi_0,(*height));
    }
    
    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)};
    }
    
    {
    static int height = 10;
    void(*block) = &__main_block_impl_0(
                                                __main_block_func_0,
                                                &__main_block_desc_0_DATA,
                                                 &height);
     height = 20;
    block->FuncPtr(block);
    }
    
    
    • 3.全局变量
    block的类型
    • block有3种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型.
      1、__ NSGlobalBlock __ ( _ NSConcreteGlobalBlock )
      2、__ NSStackBlock __ ( _ NSConcreteStackBlock )
      3、__ NSMallocBlock __ ( _ NSConcreteMallocBlock )
    block04.png block05.png
    • 没有访问auto变量

    即使访问了static全局变量block类型仍然是__ NSGlobalBlock__

    
    int age = 10;
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            void (^block)(void) = ^{
                NSLog(@"age----%d",age);
            };
            
            static int a = 100;
            void (^block1)(void) = ^{
                NSLog(@"a----%d",a);
            };
            
            NSLog(@"block'type is %@;block1'type is %@",[block class],[block1 class]);
            
        }
        return 0;
    }
    
    控制台打印的结果:2020-07-05 23:31:53.484623+0800 interview4-block的类型[5014:424923] block'type is __NSGlobalBlock__;block1'type is __NSGlobalBlock__
    
    
    • 访问auto变量

    说明:
    1、在ARC环境下的block类型是__ NSMallocBlock__(因为运行时Runtime做了太多的事导致访问了auto变量之后blockNSMallocBlock类型的block);
    2、在MRC环境下的类型是__ NSMallocBlock__

    `ARC`环境下:`__ NSMallocBlock__ `
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            int a = 100;
            
            void (^block1)(void) = ^{
                
                NSLog(@"a----%d",a);
            };
            
            NSLog(@"block1'type is %@",[block1 class]);
            
        }
        return 0;
    }
    
    

    MRC环境下的类型是__ NSStackBlock __

    block10.png
    • __ NSStackBlock __调用了copy返回的block类型是__ NSMallocBlock__

    说明:不管是ARCMRC__ NSStackBlock __类型的block只要调用了copy返回的类型都是__ NSMallocBlock__

    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            int a = 100;
            
            void (^block1)(void) = ^{
                
                NSLog(@"a----%d",a);
            };
            
            NSLog(@"block1'type is %@",[[block1 copy] class]);
            
        }
        return 0;
    }
    
    • 每一种类型的block调用copy后的结果如下所示:
    block06.png
    Blockcopy
    • ARC环境下,编译器会根据情况自动将栈上block复制到堆上,比如以下情况:
      1.block作为函数返回值时。
    #import <Foundation/Foundation.h>
    typedef void(^KXBlock)(void);
    KXBlock myBlock(){
        /**
         1.ARC环境下return时,会自动为block 调用一次copy操作,[block copy];
         2.MRC环境下return时,开发人员需要自己调用copy,[block copy];和[block release]操作。
         */
        
        KXBlock block = ^{
            NSLog(@"-------------");
        };
        return block;
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            KXBlock block = myBlock();
            
            block();
            
            NSLog(@"%@",[block class]);
        }
        return 0;
    }
    

    2.将block赋值给__strong指针时。

    #import <Foundation/Foundation.h>
    
    typedef void(^KXBlock)(void);
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            int age = 10;
            
            KXBlock blcok = ^{
                
                NSLog(@"----%d",age);
                
            };
            
            NSLog(@"%@",[blcok class]);
        }
        return 0;
    }
    
    

    3.block作为Cocoa API方法名含有UsingBlock的方法参数时。

    
    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
        
        @autoreleasepool {
        
            NSArray *array = @[];
            
            [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                
            }];
        }
        return 0;
    }
    
    

    4.block作为GCD API的方法参数时。

    
    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
        
        @autoreleasepool {
        
            //01
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{
                
            });
            
            //02
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                
            });
            
        }
        return 0;
    }
    
    
    • MRCblock属性的建议写法
      1.@property (copy, nonatomic) void (^block)(void);

    • ARCblock属性的建议写法
      1.@property (strong, nonatomic) void (^block)(void);
      2.@property (copy, nonatomic) void (^block)(void);

    相关文章

      网友评论

          本文标题:iOS开发之Block

          本文链接:https://www.haomeiwen.com/subject/eczhqktx.html