美文网首页
iOS 之 block(4.3)

iOS 之 block(4.3)

作者: 老猫_2017 | 来源:发表于2020-01-14 10:56 被阅读0次
    1. block 调用 局部变量 NSObject 时
    // source code
    #import <Foundation/NSObject.h>
    
    @interface  Person: NSObject
    @property (assign, nonatomic) int age;
    @end
    
    @implementation Person
    @end
    
    int main(int argc, char * argv[]) {
    
        Person *person = [Person new];
    
        void (^myHello)(int) = ^(int x){
            person.age = x;
        };
    
        myHello(8);
    }
    
    // block impl
    struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr; // (void (*)(__block_impl *, int)
    };
    
    // FuncPtr
    static void __main_block_func_0(struct __main_block_impl_0 *__cself, int x) {
      Person *person = __cself->person; // bound by copy
      ((void (*)(id, SEL, int))(void *)objc_msgSend)((id)person, sel_registerName("setAge:"), (int)x);
    }
    
    // block desc
    static struct __main_block_desc_0 {
      size_t reserved;
      size_t Block_size;
      void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
      void (*dispose)(struct __main_block_impl_0*);
    } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
    
    // desc copy
    static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);}
    
    // desc dispose
    static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);}
    
    // 自定义 block 声明
    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      Person *person;
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, int flags=0) : person(_person) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    
    // person new
    Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new"));
    
    // myHello 的初始化以及赋值操作
    void (*myHello)(int) = ((void (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, person, 570425344));
    
    // 调用 FuncPtr
    ((void (*)(__block_impl *, int))((__block_impl *)myHello)->FuncPtr)((__block_impl *)myHello, 8);
    

    总结:
    block 持有局部变量时,自定义block 内部有一个Person field,此时的 person 会进行 引用计数操作,我们继续往下来看
    _Block_object_assign 生效时机 捕获Person 对象 BLOCK_FIELD_IS_OBJECT 标志生效

    接下来,我们看源代码

    // When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point to do the assignment.
    void _Block_object_assign(void *destArg, const void *object, const int flags) {
        const void **dest = (const void **)destArg;
        switch (os_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) {
          case BLOCK_FIELD_IS_OBJECT:
            /*******
            id object = ...;
            [^{ object; } copy];
            ********/
    
            _Block_retain_object(object); // +1
            *dest = object;
            break;
    
          case BLOCK_FIELD_IS_BLOCK:
            /*******
            void (^object)(void) = ...;
            [^{ object; } copy];
            ********/
    
            *dest = _Block_copy(object); // block copy
            break;
        
          case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK:
          case BLOCK_FIELD_IS_BYREF:
            /*******
             // copy the onstack __block container to the heap
             // Note this __weak is old GC-weak/MRC-unretained.
             // ARC-style __weak is handled by the copy helper directly.
             __block ... x;
             __weak __block ... x;
             [^{ x; } copy];
             ********/
    // 改造后的 _Block_byref 的copy
            *dest = _Block_byref_copy(object);
            break;
            
          case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
          case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
            /*******
             // copy the actual field held in the __block container
             // Note this is MRC unretained __block only. 
             // ARC retained __block is handled by the copy helper directly.
             __block id object;
             __block void (^object)(void);
             [^{ object; } copy];
             ********/
    
            *dest = object;
            break;
    
          case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK:
          case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK  | BLOCK_FIELD_IS_WEAK:
            /*******
             // copy the actual field held in the __block container
             // Note this __weak is old GC-weak/MRC-unretained.
             // ARC-style __weak is handled by the copy helper directly.
             __weak __block id object;
             __weak __block void (^object)(void);
             [^{ object; } copy];
             ********/
    
            *dest = object;
            break;
    
          default:
            break;
        }
    }
    
    

    在来看 dispose, __block 修饰的对象,会进行 byref_release, block 会释放, 捕获的 object 引用计数-1

    // When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point
    // to help dispose of the contents
    void _Block_object_dispose(const void *object, const int flags) {
        switch (os_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) {
          case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK:
          case BLOCK_FIELD_IS_BYREF:
            // get rid of the __block data structure held in a Block
            _Block_byref_release(object);
            break;
          case BLOCK_FIELD_IS_BLOCK:
            _Block_release(object);
            break;
          case BLOCK_FIELD_IS_OBJECT:
            _Block_release_object(object);
            break;
          case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
          case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
          case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK:
          case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK  | BLOCK_FIELD_IS_WEAK:
            break;
          default:
            break;
        }
    }
    

    场景2,当有多个 对象捕获时,会发生什么?

    #import <Foundation/NSObject.h>
    
    @interface  Person: NSObject
    @property (assign, nonatomic) int age;
    @end
    
    @implementation Person
    @end
    
    
    @interface  City: NSObject
    @property (assign, nonatomic) int code;
    @end
    
    @implementation City
    @end
    
    int main(int argc, char * argv[]) {
    
        Person *person = [Person new];
        City *city = [City new];
    
        void (^myHello)(int) = ^(int x){
            person.age = x;
            city.code = 2020;
        };
    
        myHello(8);
    }
    
    struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr;
    };
    
    static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->city, (void*)src->city, 3/*BLOCK_FIELD_IS_OBJECT*/);}
    
    static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->city, 3/*BLOCK_FIELD_IS_OBJECT*/);}
    
    static struct __main_block_desc_0 {
      size_t reserved;
      size_t Block_size;
      void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
      void (*dispose)(struct __main_block_impl_0*);
    } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
    
    static void __main_block_func_0(struct __main_block_impl_0 *__cself, int x) {
        Person *person = __cself->person; // bound by copy
        City *city = __cself->city; // bound by copy
        ((void (*)(id, SEL, int))(void *)objc_msgSend)((id)person, sel_registerName("setAge:"), (int)x);
        ((void (*)(id, SEL, int))(void *)objc_msgSend)((id)city, sel_registerName("setCode:"), 2020);
    }
    
    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      Person *person;
      City *city;
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, City *_city, int flags=0) : person(_person), city(_city) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    
    int main(int argc, char * argv[]) {
    
        Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new"));
        City *city = ((City *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("City"), sel_registerName("new"));
    
        void (*myHello)(int) = ((void (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, person, city, 570425344));
    
        ((void (*)(__block_impl *, int))((__block_impl *)myHello)->FuncPtr)((__block_impl *)myHello, 8);
    }
    
    

    总结:
    可以看出,如果有多个捕获的对象时,在自定义的声明里,会明确出来,当生成代码时,保证其扩展行,真的不同的类型,都有单独的处理。

    1. 当对象被block 修饰时,会发生什么?
    #import <Foundation/NSObject.h>
    
    @interface  Person: NSObject
    @property (assign, nonatomic) int age;
    @end
    
    @implementation Person
    @end
    
    
    @interface  City: NSObject
    @property (assign, nonatomic) int code;
    @end
    
    @implementation City
    @end
    
    int main(int argc, char * argv[]) {
    
        Person *person = [Person new];
        __block City *city = [City new];
    
        void (^myHello)(int) = ^(int x){
            person.age = x;
            city.code = 2020;
        };
    
        myHello(8);
    }
    
    
    struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr;
    };
    
    static struct __main_block_desc_0 {
      size_t reserved;
      size_t Block_size;
      void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
      void (*dispose)(struct __main_block_impl_0*);
    } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
    
    static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->city, (void*)src->city, 8/*BLOCK_FIELD_IS_BYREF*/);}
    
    static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->city, 8/*BLOCK_FIELD_IS_BYREF*/);}
    
    static void __main_block_func_0(struct __main_block_impl_0 *__cself, int x) {
        __Block_byref_city_0 *city = __cself->city; // bound by ref
        Person *person = __cself->person; // bound by copy
    
        ((void (*)(id, SEL, int))(void *)objc_msgSend)((id)person, sel_registerName("setAge:"), (int)x);
        ((void (*)(id, SEL, int))(void *)objc_msgSend)((id)(city->__forwarding->city), sel_registerName("setCode:"), 2020);
    }
    
    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      Person *person;
      __Block_byref_city_0 *city; // by ref
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, __Block_byref_city_0 *_city, int flags=0) : person(_person), city(_city->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    
    struct __Block_byref_city_0 {
      void *__isa;
    __Block_byref_city_0 *__forwarding;
     int __flags;
     int __size;
     void (*__Block_byref_id_object_copy)(void*, void*);
     void (*__Block_byref_id_object_dispose)(void*);
     City *city;
    };
    
    static void __Block_byref_id_object_copy_131(void *dst, void *src) {
     _Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
    }
    
    static void __Block_byref_id_object_dispose_131(void *src) {
     _Block_object_dispose(*(void * *) ((char*)src + 40), 131);
    }
    
    int main(int argc, char * argv[]) {
    
        Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new"));
        __attribute__((__blocks__(byref))) __Block_byref_city_0 city = {(void*)0,(__Block_byref_city_0 *)&city, 33554432, sizeof(__Block_byref_city_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((City *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("City"), sel_registerName("new"))};
    
        void (*myHello)(int) = ((void (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, person, (__Block_byref_city_0 *)&city, 570425344));
    
        ((void (*)(__block_impl *, int))((__block_impl *)myHello)->FuncPtr)((__block_impl *)myHello, 8);
    }
    
    

    总结:针对__block 修饰的,会构造一个 byref ,持有被修饰的对象
    在进行,copy,dispose ,有对应的函数

    int main(int argc, char * argv[]) {
    
        Person *person = [Person new];
        __block City *city = [City new];
        __block int y = 0;
    
        void (^myHello)(int) = ^(int x){
            person.age = x;
            city.code = 2020;
            y = 10;
        };
    
        myHello(8);
    }
    
    struct __Block_byref_city_0 {
      void *__isa;
    __Block_byref_city_0 *__forwarding;
     int __flags;
     int __size;
     void (*__Block_byref_id_object_copy)(void*, void*);
     void (*__Block_byref_id_object_dispose)(void*);
     City *city;
    };
    
    struct __Block_byref_y_1 {
      void *__isa;
    __Block_byref_y_1 *__forwarding;
     int __flags;
     int __size;
     int y;
    };
    
    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      Person *person;
      __Block_byref_city_0 *city; // by ref
      __Block_byref_y_1 *y; // by ref
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, __Block_byref_city_0 *_city, __Block_byref_y_1 *_y, int flags=0) : person(_person), city(_city->__forwarding), y(_y->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    
    static struct __main_block_desc_0 {
      size_t reserved;
      size_t Block_size;
      void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
      void (*dispose)(struct __main_block_impl_0*);
    } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
    
    static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->city, (void*)src->city, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_assign((void*)&dst->y, (void*)src->y, 8/*BLOCK_FIELD_IS_BYREF*/);}
    
    static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->city, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_dispose((void*)src->y, 8/*BLOCK_FIELD_IS_BYREF*/);}
    
    int main(int argc, char * argv[]) {
    
        Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new"));
        __attribute__((__blocks__(byref))) __Block_byref_city_0 city = {(void*)0,(__Block_byref_city_0 *)&city, 33554432, sizeof(__Block_byref_city_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((City *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("City"), sel_registerName("new"))};
        __attribute__((__blocks__(byref))) __Block_byref_y_1 y = {(void*)0,(__Block_byref_y_1 *)&y, 0, sizeof(__Block_byref_y_1), 0};
    
        void (*myHello)(int) = ((void (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, person, (__Block_byref_city_0 *)&city, (__Block_byref_y_1 *)&y, 570425344));
    
        ((void (*)(__block_impl *, int))((__block_impl *)myHello)->FuncPtr)((__block_impl *)myHello, 8);
    }
    
    

    总结:可以看出 __block 修饰的基本数据类型,是没有copy,dispose操作的

    相关文章

      网友评论

          本文标题:iOS 之 block(4.3)

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