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;
}
};
1.1 Type
View method
- Check
isa
[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 (theARC
mode needs to be turned off, otherwise ARC will help the code optimize the callcopy
)__NSMallocBlock__
:__NSStackBlock__
Tuition completedcopy
Method
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 theauto
variable
-
If the block is copied to the heap
- For meetings
block
Internalcopy
Function.__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)
- For meetings
-
block removed from heap
- For meetings
block
Internaldispose()
Function:__main_block_impl_0
->__main_block_desc_0
->void (*dispose)(struct __main_block_impl_0*);
dispose
will callvoid _Block_object_dispose(const void *, const int)
void _Block_object_dispose(const void *, const int)
will automatically release the referencedauto
variable, similar torelease
- For meetings
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
__block
Global variables and static variables cannot be modified__block
will automatically wrap local variables into objects (includingisa
andstruct
), so blcok will capture the address of this object. The life cycle is the same as block- Object's
__blcok
will generatecopy
anddispose
methods, but non-object will not__main_block_desc_0
'scopy
anddispose
just copy the structure, strong reference- Instance structure
__Block_byref_person_1
internalcopy
anddispose
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 following
struct__Block_byref_person_1
will call the internaldispose
to destroy its ownMJPerson *__strong person;
instance variable (if it is weak If you modify it, you should leave it alone).
copy
The process is as shown below. Destruction process, go back the same way.
Reference diagram
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
- run
per.myBlock();
block
The internal code will manually set__Block_byref_person_1 内部的per
to nil. break an arrow- Wait after the
block
life cycle, and another arrow will be broken.
The final structure is as follows:
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.