iOS 之 block(4.3)

2020-01-14  本文已影响0人  老猫_2017
  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操作的

上一篇下一篇

猜你喜欢

热点阅读