OC Learning Record Essay Block

Total information
All are essays and notes. irregular. Some of them are teacher MJ’s course notes.

1. Block

  • Block is essentially an oc object, and it contains an isa pointer internally.
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};

struct __main_block_impl_0 {
    
    
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  MJPerson *__strong person;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, MJPerson *__strong _person, int flags=0) : person(_person) {
    
    
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

Insert image description here
Insert image description here

1.1 Type

View method

  • Checkisa [self class] [[self class] superclass]
  • View the compiled cpp file (there is only one type compiled, which will be modified during runtime)

type

  • __NSGlobalBlock__: No access to auto variables (calling copy has no effect)
  • __NSStackBlock__: The auto variable is accessed (the ARC mode needs to be turned off, otherwise ARC will help the code optimize the call copy)
  • __NSMallocBlock__: __NSStackBlock__Tuition completedcopyMethod

inheritance line

can be obtained by taking superclass. In the end, inheritance is the same as NSObject

  • __NSGlobalBlock__ -> __NSGlobalBlock -> NSBlock -> NSObject

1.2Copy Release

  • block When a variable of object type is accessed internallyauto

    • block is on the stack, and there will be no strong reference to the auto variable
  • If the block is copied to the heap

    • For meetingsblockInternalcopyFunction. __main_block_impl_0 -> __main_block_desc_0 -> void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
    • copy will call_Block_object_assign(void *, const void *, const int)
    • _Block_object_assign(void *, const void *, const int) will operate according to the modifiers of the auto variable (__strong, __weak, __unsafe_unretained), similar to retain (form Strong reference, weak reference)
  • block removed from heap

    • For meetingsblock Internaldispose()Function:__main_block_impl_0 -> __main_block_desc_0 -> void (*dispose)(struct __main_block_impl_0*);
    • disposewill callvoid _Block_object_dispose(const void *, const int)
    • void _Block_object_dispose(const void *, const int) will automatically release the referenced auto variable, similar to release
copy 和 dispose 在访问对象的时候,会自动生成。
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};

1.3 __Block

  • __blockGlobal variables and static variables cannot be modified
  • __block will automatically wrap local variables into objects (including isa and struct), so blcok will capture the address of this object. The life cycle is the same as block
  • Object's__blcok will generate copy and dispose methods, but non-object will not
    • __main_block_desc_0's copy and dispose just copy the structure, strong reference
    • Instance structure__Block_byref_person_1 internal copy and dispose will copy the real instance variables inside the structure, depending on Modifierstrong orweak
    • When the block is destroyed,__main_block_desc_0'sdispose will be called and destroyedstruct__Block_byref_person_1.
    • The followingstruct__Block_byref_person_1 will call the internal dispose to destroy its own MJPerson *__strong person; instance variable (if it is weak If you modify it, you should leave it alone).

copyThe process is as shown below. Destruction process, go back the same way.

Please add image description

Reference diagram

Insert image description here

The specific source code is as follows

源代码,有两个__block
	__block int age = 10;
    __block MJPerson *person = [[MJPerson alloc] init];
    MJBlock b = ^(void) {
    
    
        age = 11;
        person.age = 12;
        NSLog(@"---%d", person.age);
    };

The result after cpp compilation

Typedef void (*MJBlock)(void);

struct __Block_byref_age_0 {
    
    
  void *__isa; //类型
  //__forwarding 指向自己的地址, 如果是copy后,就会指向堆中的地址, 如果没有copy 就指向自己
__Block_byref_age_0 *__forwarding; 
 int __flags;
 int __size;
 int age; // __forwarding 中的age才是真正的值.
};

//对象的__blcok 会生成 copy  和 dispose 方法
struct __Block_byref_person_1 {
    
    
  void *__isa;
__Block_byref_person_1 *__forwarding;  //指向自己的地址
 int __flags;
 int __size;
 //下面的两个方法啊才是 strong 和copy的选择 实现
 void (*__Block_byref_id_object_copy)(void*, void*); 
 void (*__Block_byref_id_object_dispose)(void*);
 MJPerson *__strong person;  //这里strong
};
static struct __main_block_desc_0 {
    
    
  size_t reserved;
  size_t Block_size;
  //这里copy 会统一拷贝 __Block_byref_age_0 和 __Block_byref_person_1 struct 到堆中,都是strong的引用
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
   //这里release 会统一拷贝 __Block_byref_age_0 和 __Block_byref_person_1 struct  到堆中,都是strong的引用
  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};


struct __main_block_impl_0 {
    
    
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_age_0 *age; // by ref.  变量1  强引用
  __Block_byref_person_1 *person; // by ref 变量2   强引用 
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, __Block_byref_person_1 *_person, int flags=0) : age(_age->__forwarding), person(_person->__forwarding) {
    
    
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};


//CPP 内部的main实现
int main(int argc, const char * argv[]) {
    
    
    /* @autoreleasepool */ {
    
     __AtAutoreleasePool __autoreleasepool; 

        __attribute__((__blocks__(byref))) __Block_byref_age_0 age = {
    
    (void*)0,(__Block_byref_age_0 *)&age, 0, sizeof(__Block_byref_age_0), 10};
        
         __Block_byref_person_1 person = {
    
    0,&person, 33554432, sizeof(__Block_byref_person_1), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, objc_msgSend)((id, SEL))objc_msgSend)(objc_getClass("MJPerson"), sel_registerName("alloc")), sel_registerName("init"))};
        
        MJBlock b = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_age_0 *)&age, (__Block_byref_person_1 *)&person, 570425344));

    }
    return 0;
}


// 下面为 person 结构体的 copy 和 dispose 方法的实现
// 这里才会 真正的对 person 实例进行 strong 或者 weak 的属性. 
// 而 __main_block_desc_0 方法的 copy 和 dispose 都是强引用对象
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);
}

TODO: There is another one after 3
_Block_object_assign((void*)&dst->person, (void*)src->person, 8//);}BLOCK_FIELD_IS_BYREF

_Block_object_assign((char*)dst + 40, *(void * ) ((char)src + 40), 131);

1.4 Three modifiers to solve circular references

__unsafe_unretained VS __weak

__weak typedef(self) weakSelf = self;
__unsafe_unretained typedef(self) weakSelf = self;

self.block = ^{
 	self.age = 5;
};

When both are held by the block, no circular reference will be generated.

  • __weak: When the pointed object is destroyed, the pointer will be automatically set to nil
  • __unsafe_unretained: Unsafe. When the pointed object is destroyed, the address stored by its own pointer will not change, and wild pointers will be generated.

__block

__block Person *per = [Person new];
per.age = 44;

per.myBlock = ^{
	per.age = 55;
	per = nil;
};
per.myBlock();

As shown in the above code, __block can also solve the circular reference, but the block must be executed once and per is manually set to nil in the block. Only then can we break the triangle cycle.

The reference structure is as follows

如果用weak修饰这里就是虚线
per
myBlcok
__Block_byref_person_1 内部的per
  1. runper.myBlock();
  2. blockThe internal code will manually set __Block_byref_person_1 内部的per to nil. break an arrow
  3. Wait after the block life cycle, and another arrow will be broken.

The final structure is as follows:

per
myBlcok
__Block_byref_person_1 内部的per

so it can break the circular reference. However, the circular reference cannot be broken if the block is not executed, so needs to be used with caution.

1.5 The difference between strong and copy modifiers

@propert (nonatomic, strong) MyBlock block;
@propert (nonatomic, copy) MyBlock block;

There is no difference between the two inARC mode.
Because when strong is used, ARC mode will also automatically copy be placed on the heap.
The reason why copy is recommended is to maintain the MRC habit, or the reminder displayed is copied to the heap.

Guess you like

Origin blog.csdn.net/goldWave01/article/details/121445902