iOS에서 blcok의 본질 설명
25063 단어 iOS
더 좋은 독서 체험을 원하신다면, 저의 개발 노트를 방문하시기 바랍니다.
blcok의 본질은 하나의 대상이다
main.m
의 코드int main(int argc, const char * argv[]) {
int age = 18;
static int height = 55;
void (^block)(int) = ^(int pa) {
NSLog(@"--block- auto --%d",age);
NSLog(@"--block- static --%d",height);
};
NSLog(@"---%@",[block class]);
NSLog(@"---%@",[[block class] superclass]);
NSLog(@"---%@",[[[block class] superclass] superclass]);
NSLog(@"---%@",[[[[block class] superclass] superclass] superclass]);
block(10);
}
보이는 Block을 인쇄하는 것도 oc 대상입니다.
2019-06-08 11:38:23.353777+0800 Tes[41864:3485021] —NSStackBlock 2019-06-08 11:38:23.354053+0800 Tes[41864:3485021] —__NSStackBlock 2019-06-08 11:38:23.354091+0800 Tes [41864:3485021] - NSBlock 2019-06-08 11:3811:285275+0800 Tes [41864:3485021] - Block-국부 auto 변수의 포획 - 18864:08 11:38:38:2834344+0800 Tes [41864:3485021] - 국부 auto 변수의 포획 - 국부 변수
상기 코드를
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m
를 통해 c++ 코드로 전환하면 block
의 구조를 볼 수 있습니다//block
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int age;
int *height;
//
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int *_height, int flags=0) : age(_age), height(_height) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
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)};
blcok의 실현은 첫 번째 매개 변수로 전송되고 포획된 변수는 뒤에 매개 변수로 되어
__main_block_impl_0
구조체의 구조 함수를 호출하여 Block의 생성을 실현한다.int main(int argc, const char * argv[]) {
int age = 18;
static int height = 55;
void (*block)(int) = ((void (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age, &height));
//
void (*block)(int) = &__main_block_impl_0(
__main_block_func_0,
&__main_block_desc_0_DATA,
age,
&height);
}
block의 구체적인 구현 봉인된 함수
static void __main_block_func_0(struct __main_block_impl_0 *__cself, int pa) {
int age = __cself->age; // bound by copy
int *height = __cself->height; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pg_vnxk1kl519z1ks1hddc4mr0h0000gn_T_main_53cf21_mi_0,age);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pg_vnxk1kl519z1ks1hddc4mr0h0000gn_T_main_53cf21_mi_1,(*height));
}
Block의 호출:
block(10);
block
타입이기 때문에 __main_block_impl_0
타입__block_impl
타입imp
을 추출한 다음imp
추출FuncPtr
을 통해 호출합니다.그런데 여기는 왜 직접 blcok
를 __block_impl
유형으로 강제 전환했습니까?impl
는 __main_block_impl_0
구조체의 첫 번째 요소로서 __main_block_impl_0
변수의 주소가 바로 그 첫 번째 요소의 주소이기 때문에 여기서 강제 변환이 실현될 수 있다.((void (*)(__block_impl *, int))((__block_impl *)block)->FuncPtr)((__block_impl *)block, 10);
//
(block->FuncPtr)(block, 10);
//
(block->imp->FuncPtr)(block, 10);
blcok의 변수 포획
__main_block_impl_0
구조체를 통해 여러 개int age int *height
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int age;
int *height;
}
//
static void __main_block_func_0(struct __main_block_impl_0 *__cself, int pa) {
// , block
int age = __cself->age; // bound by copy
int *height = __cself->height; // bound by copy
}
auto
로 수식된 국부 변수(국부 변수, 기본값은 auto): 국부 변수이기 때문에 자동으로 소각되고, Block 호출 전에 소각되면 Block 호출 시 얻은 값에 문제가 발생하기 때문에 값 전달을 실행합니다.static
로 수식된 국부 변수: 이것도 국부 변수이지만 static
로 수식되었기 때문에 변수 작용역이 생겨서 자동으로 소각되지 않습니다. 그러면 Block이 호출될 때 정확한 값을 얻을 수 있기 때문에 바늘 전달에 문제가 되지 않습니다.int age_ = 18;
static int height_ = 55;
int main(int argc, const char * argv[]) {
void (^block)(int) = ^(int pa) {
NSLog(@"--block- auto --%d",age_);
NSLog(@"--block- static --%d",height_);
};
NSLog(@"---%@",[block class]);
NSLog(@"---%@",[[block class] superclass]);
NSLog(@"---%@",[[[block class] superclass] superclass]);
NSLog(@"---%@",[[[[block class] superclass] superclass] superclass]);
block(10);
}
c++로 전환
blcok
된 구조체는 age_
와height_
가 없는 것을 발견했다. 그들은 전역 변수이기 때문에 언제든지 어디든지 접근할 수 있기 때문에 포획할 필요가 없다.struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
}
//
static void __main_block_func_0(struct __main_block_impl_0 *__cself, int pa) {
// ,
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pg_vnxk1kl519z1ks1hddc4mr0h0000gn_T_main_ccc8d0_mi_2,age_);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_pg_vnxk1kl519z1ks1hddc4mr0h0000gn_T_main_ccc8d0_mi_3,height_);
}
글로벌 변수는 캡처되지 않습니다.
blcok 유형
int main(int argc, const char * argv[]) {
int age = 18;
//__NSStackBlock__
NSLog(@"----%@",[^(int pa) {
NSLog(@"--block---%d",age);
} class]);
//__NSGlobalBlock__
void (^block)(int) = ^(int pa) {
NSLog(@"---");
};
NSLog(@"----%@",[block class]);
//__NSMallocBlock__
void (^block1)(int) = ^(int pa) {
NSLog(@"--block---%d",age);
};
NSLog(@"----%@",[block1 class]);
}
인쇄:
2019-06-08 11:51:08.351813+0800 Tes[42036:3500881] ----NSStackBlock 2019-06-08 11:51:08.352169+0800 Tes[42036:3500881] ----NSGlobalBlock 2019-06-08 11:51:08.352201+0800 Tes[42036:3500881] ----NSMallocBlock
메모리에서 지상 주소에서 높은 주소로:
__NSStackBlock__형식의blcok는oc대상에 강한 인용이 없습니다
typedef void(^RTBlock)(int);
int main(int argc, const char * argv[]) {
RTBlock block;
{
RTPerson *person = [[RTPerson alloc] init];
NSLog(@"--block---%@",[^(int pa) {
NSLog(@"--block---%@",person);
} class]);
}
NSLog(@"--block---%@",[block class]);
}
인쇄:
2019-06-10 13:04:08.687481+0800 Tes[42877:3569172] --block—NSStackBlock 2019-06-10 13:04:08.687816+0800 Tes[42877:3569172] dealloc 2019-06-10 13:04:08.687839+0800 Tes[42877:3569172] --block—(null)
block
의 유형은 stack
이기 때문에 person
를 강제로 인용하지 않습니다.만NSMallocBlock__형식의blcok는oc대상에 강한 인용이 있습니다
int main(int argc, const char * argv[]) {
RTPerson *person = [[RTPerson alloc] init];
//__NSMallocBlock__
void (^block1)(int) = ^(int pa) {
NSLog(@"--block---%@",person);
};
NSLog(@"----%@",[block1 class]);
}
c++ 코드로 전환한 후
__main_block_desc_0
구조체에 두 개의 함수 바늘이 더 있는 것을 발견하였다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};
__main_block_copy_0, 이 함수는 이 Block에서 포획한oc 대상의 유형이 약한 인용인지 강한 인용인지 여부에 따라 강한 인용을 할 수 있습니다
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*/);
}
__main_block_dispose_0, 이 함수는 강력한 인용을 방출하는 데 쓰인다
static void __main_block_dispose_0(struct __main_block_impl_0*src) {
_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
Block 내부 변수 수정
typedef void(^RTBlock)(int);
int main(int argc, const char * argv[]) {
__block int age = 18;
RTBlock block = ^(int pa) {
NSLog(@"--block---%d",age);
age = pa;
NSLog(@"--block---%d",age);
};
block(1);
}
c++ 코드로 전환한 후 이전의 구조와 차이가 있음을 발견했다. 이전의 변수 유형은 변수의 자체 유형이고age는
__Block_byref_age_0
유형이 되었다.struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_age_0 *age; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
__Block_byref_age_0
구조체의 코드는struct __Block_byref_age_0 {
void *__isa;
__Block_byref_age_0 *__forwarding;
int __flags;
int __size;
int age;
};
__block int age = 18;
에서 c++ 코드로 변경:__attribute__((__blocks__(byref))) __Block_byref_age_0 age = {(void*)0,(__Block_byref_age_0 *)&age, 0, sizeof(__Block_byref_age_0), 18};
//
__Block_byref_age_0 age = {
0,
&age, //__forwarding
0,
sizeof(__Block_byref_age_0),
18 //
};
Block을 만들 때 위에서 생성된
__Block_byref_age_0 age
의 주소를 자신의 내부에 부여age
RTBlock block = (
(void (*)(int))&__main_block_impl_0((void *)__main_block_func_0,
&__main_block_desc_0_DATA,
(__Block_byref_age_0 *)&age,
570425344));
__main_block_impl_0
함수 내부에서age의 값을 수정한 다음에 수정age
의 값을 실현하였다.static void __main_block_func_0(struct __main_block_impl_0 *__cself, int pa) {
__Block_byref_age_0 *age = __cself->age; // bound by ref
...
(age->__forwarding->age) = pa;
...
}
그런데 왜
__Block_byref_age_0
에서age
의 값을 수정하고 바깥의 값도 바뀌었을까요? 그들의 주소는 같을까요?다음은 프린트 주소를 통해 증명합니다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*);
// , void,
void (*copy)(void);
void (*dispose)(void);
};
struct __Block_byref_age_0 {
void *__isa;
struct __Block_byref_age_0 *__forwarding;
int __flags;
int __size;
int age;
};
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;
struct __Block_byref_age_0 *age; // by ref
};
typedef void(^RTBlock)(int);
int main(int argc, const char * argv[]) {
__block int age = 18;
RTBlock block = ^(int pa) {
NSLog(@"--block---%d",age);
age = pa;
NSLog(@"--block---%d",age);
};
struct __main_block_impl_0 *s_block = (__bridge struct __main_block_impl_0 *) block;
NSLog(@"-- age ---%p",&age);
NSLog(@"-- age ---%p",&s_block->age->age);
}
인쇄 결과:
2019-06-08 14:30:48.880799+0800 Tes [43886:3665093] - 외부age 주소 - 0x10180cd28 2019-06-08 14:30:48.881041+0800 Tes [43886:3665093] - 구조체 내부age 주소 - 0x10180cd28
__block
를 사용했기 때문에__main_block_desc_0
구조체에도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};
그래서
block
의__Block_byref_age_0 *age
이 구조체 지침을 쌓아 올리다static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->age, (void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}
__Block_byref_id_object_copy
와 __Block_byref_id_object_dispose
가 더 나와 OC 대상에 대한 메모리 관리struct __Block_byref_person_0 {
void *__isa;
__Block_byref_person_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
RTPerson *person;
};
__Block_byref_id_object_copy_131, 이 함수는 이 Block에서 포획한oc 대상의 유형에 따라 약인용인지 강인용인지 여부에 따라 강인용을 합니다
static void __Block_byref_id_object_copy_131(void *dst, void *src) {
_Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
/*__isa: 8 ,
__forwarding: 8 ,
int __flags: 4 ,
int __size: 4 ,
__Block_byref_id_object_copy: 8
__Block_byref_id_object_dispose: 8
40
dst + 40 person
*/
}
__Block_byref_id_object_dispose_131, 이 함수는 강력한 인용을 방출하는 데 쓰인다
static void __Block_byref_id_object_dispose_131(void *src) {
_Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}
예:
사용하지 않음
weak
RTBlock block;
{
__block RTPerson *person = [[RTPerson alloc] init];
block = ^(int pa) {
NSLog(@"--block---%@",person);
};
}
NSLog(@"--block ---%@",[block class]);
인쇄:
2019-06-08 14:12:13.198105+0800 Tes [45184:3784877] - Block 유형 - NSMallocBlock 2019-06-08 14:12:17.398071+0800 Tes [45184:378487] RTPerson dealloc
사용
weak
손질RTBlock block;
{
RTPerson *person = [[RTPerson alloc] init];
__block __weak RTPerson *weakP = person;
block = ^(int pa) {
NSLog(@"--block---%@",weakP);
};
}
NSLog(@"--block ---%@",[block class]);
인쇄:
2019-06-08 14:13:22.198105+0800 Tes [45184:378487] RTPerson dealloc 2019-06-08 14:13:26.398071+0800 Tes [45184:3784877] - Block 유형 - NSMallocBlock
참고:
MRC 시
__Block_byref_id_object_copy_131
는 OC 대상을 강제로 인용하지 않습니다!!!RTBlock block;
{
__block RTPerson *person = [[RTPerson alloc] init];
block = [^(int pa) {
NSLog(@"--block---%@",person);
} copy] ;
[person release];
}
NSLog(@"--block ---%@",[block class]);
인쇄:
2019-06-08 14:17:43.198105+0800 Tes [45184:378487] RTPerson dealloc 2019-06-08 14:17:47.398071+0800 Tes[45184:3784877] - Block 유형 - NSMallocBlock
더 좋은 독서 체험을 원하신다면, 저의 개발 노트를 방문하시기 바랍니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
View의 레이아웃 방법을 AutoLayout에서 따뜻한 손 계산으로 하면 성능이 9.26배로 된 이야기이 기사는 의 15 일째 기사입니다. 어제는 에서 이었습니다. 손 계산을 권하는 의도는 없고, 특수한 상황하에서 계측한 내용입니다 화면 높이의 10 배 정도의 contentView가있는 UIScrollView 레이아...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.