iOS 에서 block 변수 캡 처 원리 에 대한 상세 한 분석
Block 은 C 언어 등급 과 실행 시의 특징 입 니 다.Block 은 코드 논 리 를 패키지 하고{}로 묶 었 습 니 다.표준 C 언어의 함수/함수 포인터 와 비슷 합 니 다.그 밖 에 block 은 정의 환경 에서 변 수 를 참조 할 수 있 습 니 다.이 점 은 다른 각종 언어 에서 말 하 는'폐쇄'와 매우 유사 한 개념 이다.iOS 에서 block 은 코드 패 키 징 을 매개 변수 로 전달 하 는 등 응용 장면 이 많 습 니 다.이 는 dispatch 병행(Operation 에 도 BlockOperation)과 completion 비동기 반전 등 을 사용 하 는 데 널리 활용 된다.
다 중 스 레 드
집합
네트워크 리 셋 요청
Block 의 역할
4.567917.특정한 코드 를 저장 하 는 데 사용 되 며 적당 한 시기 에 다시 호출 할 수 있 습 니 다기능 은 함수 와 방법 과 유사 하 다.
변수 캡 처
1:캡 처 가능 변수 변경 불가
부분 변수
2:캡 처 가능 하 며 변 수 를 수정 할 수 있 습 니 다.
전역 변수
정적 변수
원리 분석:
1.부분 변 수 는 왜 캡 처 되 었 는 지 수정 할 수 없습니다.
int a = 10;
void (^blcok)() = [^{
NSLog(@"%d",a);
} copy];
a=20;
blcok(); // log : a = 10
결 과 는 모두 가 알 고 있 을 텐 데 왜 그 럴 까?클 램 핑 으로 한번 바 꿔 보도 록 하 겠 습 니 다.
block 정의 로 볼 때
void (*blcok)() = (void (*)())((id (*)(id, SEL))(void *)objc_msgSend)((id)((void (*)())&__ZMX__blockTest_block_impl_0((void *)__ZMX__blockTest_block_func_0, &__ZMX__blockTest_block_desc_0_DATA, a)), sel_registerName("copy"));
block 의 실현 은ZMX__blockTest_block_impl_0.구조 체 의 구조 방법 으로 정 의 된 것 입 니 다.이 구조 체 를 살 펴 보 겠 습 니 다.
struct __ZMX__blockTest_block_impl_0 {
struct __block_impl impl;
struct __ZMX__blockTest_block_desc_0* Desc;
int a;
__ZMX__blockTest_block_impl_0(void *fp, struct __ZMX__blockTest_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
impt:
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
isa:Class 를 가리 키 는 지침flags:일부 표지
reserced:보 존 된 변수 들
함수 포인터
__ZMX__blockTest_block_desc_0:
static struct __ZMX__blockTest_block_desc_0 {
size_t reserved;
size_t Block_size;
} __ZMX__blockTest_block_desc_0_DATA = { 0, sizeof(struct __ZMX__blockTest_block_impl_0)};
reserced:보류 변수크기:메모리 크기
__ZMX__blockTest_block_impl_0 구조 방법
우 리 는 이 구조 방법 에 네 개의 매개 변수 가 있다 는 것 을 볼 수 있다.
void *fp:
struct __ZMX__blockTest_block_desc_0 *desc: desc
int _a:
int flags=0:
우 리 는 Block 의 정 의 를 간소화 합 니 다.
void (*blcok)() = ((void (*)())&__ZMX__blockTest_block_impl_0((void *)__ZMX__blockTest_block_func_0, &__ZMX__blockTest_block_desc_0_DATA, a));
우리 가 정의 할 때 이미 a 를 매개 변수 로 전달 한 것 을 볼 수 있다.즉,정 의 를 내 릴 때 우리 의 block 은 a 의 값 을 얻 었 고 뒤에서 a 의 값 을 어떻게 수정 하 든 간 에.우리 가 block 내부 에서 가 져 온 a 는 모두 정의 할 때 들 어 오 는 값 입 니 다.이것 은 block 이 국부 변 수 를 포착 할 수 있 지만 수정 할 수 없 는 이유 입 니 다.2.1 전역 변 수 는 캡 처 할 수도 있 고 수정 할 수도 있 습 니 다.
(void)blockTest
{
void (^blcok)() = [^{
NSLog(@"%d",a);
} copy];
a = 20;
blcok(); // log : 20
}
클 램 핑 으로 한번 바 꿔 보도 록 하 겠 습 니 다.같은 부분 을 반복 하지 않 겠 습 니 다.이 럴 때 blcok 의 구조 함 수 를 정의 하 는 것 은 이전 인자 a 가 들 어 오지 않 았 음 을 알 수 있 습 니 다.
NSLog 함 수 를 호출 합 니 다=위ZMX__blockTest_block_func_0 함수
static void __ZMX__blockTest_block_func_0(struct __ZMX__blockTest_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_47_6nlw9jbn3fb7c8lb1km1rzmm0000gn_T_ZMX_70ee3a_mi_0,a);
}
우리 가 block 을 호출 할 때,만약 당신 이 이전에 a 의 값 을 수정 했다 면,인쇄 한 것 은 반드시 새 값 입 니 다.2.2 정적 변 수 는 캡 처 할 수도 있 고 수정 할 수도 있 습 니 다.
(void)blockTest
{
static int a = 10;
void (^blcok)() = [^{
NSLog(@"%d",a);
} copy];
a = 20;
blcok(); //log : 20
}
클 램 핑 으로 한번 바 꿔 보도 록 하 겠 습 니 다.구조 함 수 를 통 해 우 리 는 볼 수 있 습 니 다.이때 입 삼 에 int* 가 하나 더 들 어 갔 습 니 다.a,a 의 주 소 를 전 달 했 습 니 다.인쇄 함수ZMX__blockTest_block_func_0 도 마찬가지 로 같은 메모리 주소 의 값 을 가 져 오 는 작업 입 니 다.so,우 리 는 a 를 방문 할 수 있 을 뿐만 아니 라 a 도 수정 할 수 있 습 니 다.
2.3 __block 수식 변 수 는 캡 처 할 수도 있 고 수정 할 수도 있 습 니 다.
(void)blockTest
{
__block int a = 10;
void (^blcok)() = [^{
NSLog(@"%d",a);
} copy];
a = 20;
blcok();// log : 20
}
클 램 핑 으로 한번 바 꿔 보도 록 하 겠 습 니 다.아이고!이때 의 구조 체ZMX__blockTest_block_impl_0 의 a 는 구조 체 지침 이 되 었 다.이상 하 다.이 구조 체 를 살 펴 보 자.
struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
int a;
};
isa: Class
forwarding: a
flags:
size:
a:
저희 블록 테스트 함수 다시 한 번 볼 게 요.
static void _I_ZMX_blockTest(ZMX * self, SEL _cmd) {
__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 10};
void (*blcok)() = (void (*)())((id (*)(id, SEL))(void *)objc_msgSend)((id)((void (*)())&__ZMX__blockTest_block_impl_0((void *)__ZMX__blockTest_block_func_0, &__ZMX__blockTest_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344)), sel_registerName("copy"));
(a.__forwarding->a) = 20;
((void (*)(__block_impl *))((__block_impl *)blcok)->FuncPtr)((__block_impl *)blcok);
}
이때 변수 a 는 로 변 했다.Block_byref_a_0 구조 체,우리 가 초기 화 할 때 a 에 게 준 주소 와 a 의 값 이 모두 들 어 가 는 것 을 볼 수 있 습 니 다.
a = 20 -> (a.__forwarding->a) = 20
다시 값 을 부여 합 니 다.저 희 는 a 가 가리 키 는 메모리 주소 의 value 를 수정 하여 a 의 값 을 수정 합 니 다.인쇄 함수
static void __ZMX__blockTest_block_func_0(struct __ZMX__blockTest_block_impl_0 *__cself) {
__Block_byref_a_0 *a = __cself->a; // bound by ref
NSLog((NSString *)&__NSConstantStringImpl__var_folders_47_6nlw9jbn3fb7c8lb1km1rzmm0000gn_T_ZMX_c9e1ad_mi_0,(a->__forwarding->a));
}
블록 이 캡 처 한 a 의 메모리 주소 에 대응 하 는 value 를 먼저 가 져 온 다음 인쇄 합 니 다.그래서 우 리 는 a 의 값 을 캡 처 하고 수정 할 수 있 습 니 다.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Swift의 패스트 패스Objective-C를 대체하기 위해 만들어졌지만 Xcode는 Objective-C 런타임 라이브러리를 사용하기 때문에 Swift와 함께 C, C++ 및 Objective-C를 컴파일할 수 있습니다. Xcode는 S...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.