Objective-C 의 데이터 구 조 를 깊이 이해 하 다.

유형 적 구조
OC 의 코드 는 밑바닥 에서 이 루어 지고 C,C++를 사용 하기 때문에 OC 의 클래스 구 조 를 연구 하려 면 OC 의 코드 를 C++의 코드 로 바 꾸 면 된다.먼저 NSObject 의 구조 가 어떤 지 살 펴 보고 파일 을 만 들 고 다음 코드 를 간단하게 작성 합 니 다.

// CustomFile.m
#import <Foundation/Foundation.h>
void test() {
 [NSObject alloc];
}
터미널 진입,명령 입력:
clang -rewrite-objc CustomFile.m
기본적으로 CustomFile.cpp 파일 을 생 성 합 니 다.이 명령 은 생 성 된 코드 가 많 을 뿐만 아니 라 xcun 명령 을 사용 하여 특정한 구 조 를 지정 할 수도 있다.
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc CustomFile.m -o CustomFile_arm64.cpp
이렇게 CustomFilearm 64.cpp 파일 에 실제 컴퓨터 의 실행 코드 가 생 성 됩 니 다.비교 해 보면 CustomFilearm 64.cpp 파일 은 CustomFile.cpp 보다 훨씬 작 지만 NSObject 의 실제 구 조 를 볼 수 있 습 니 다.
임의의.cpp 파일 을 열 면 다음 정 의 를 찾 을 수 있 습 니 다.

struct NSObject_IMPL {
 Class isa;
};
그 중에서 Class 의 정 의 는 다음 과 같다.

typedef struct objc_class *Class;
실제 NSObject 류 의 성명 이 어떤 지 다시 한 번 살 펴 보 겠 습 니 다.

@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
 Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
간소화 한 후에 다음 과 같다.

@interface NSObject {
 Class isa;
}
아무튼 클 라 스 는 지침 입 니 다.NSObjectIMPL 은 NSObject 와 구조 적 으로 매우 유사 한 구조 체 다.
2.계승 후의 구조
Person.m 파일 을 만 들 고 NSObject 에 계승 할 Person 클래스 를 만 듭 니 다.코드 작성 은 다음 과 같 습 니 다:

// Person.m
#import <Foundation/Foundation.h>

//     
@interface Person : NSObject
@end

//     
@implementation Person
@end

//     
@interface Student : Person
@end

//     
@implementation Student
@end
그 중에서 Person 은 NSObject 에 계승 되 었 고 Student 는 Person 에 계승 되 었 기 때문에.cpp 파일 에서 이러한 정 의 를 찾 았 습 니 다.

struct Person_IMPL {
 struct NSObject_IMPL NSObject_IVARS;
};

struct Student_IMPL {
 struct Person_IMPL Person_IVARS;
};
NSObject_IVARS 는 이 이름 을 보면 부계 의 모든 ivar 를 물 려 받 았 다 는 것 을 알 수 있다.
한 가지 방법 을 알 게 된 것 같다.
NSObject 에 서 는 Class 형식의 구성원 변수 isa 만 있 습 니 다.구성원 속성 을 사용자 정의 하지 않 은 상태 에서 계승 하 는 하위 클래스 의 ivar 는 모두 부모 클래스 에서 나 옵 니 다.
Person 과 Student 에 멤버 변 수 를 정의 한다 면 다음 과 같 습 니 다.

struct Person_IMPL {
 struct NSObject_IMPL NSObject_IVARS;
 int _no;
};

struct Student_IMPL {
 struct Person_IMPL Person_IVARS;
 int _age;
};
마침내 클 라 스 의 일부 방법 에 대해 진일보 한 이 해 를 가지 게 되 었 다.
3.첨가 방법 후의 구조
FunClass.m 파일 을 만 듭 니 다.코드 는 다음 과 같 습 니 다.

// FunClass.m
#import <Foundation/Foundation.h>

//     
@interface FunClass : NSObject
- (void)testInstance;
+ (void)testClass;
@end

//     
@implementation FunClass
- (void)testInstance {
 
}

+ (void)testClass {
 
}
@end
마지막 으로.cpp 에서 클래스 의 구 조 는 아무런 변화 가 없 음 을 발 견 했 습 니 다.다음 과 같 습 니 다.

struct FunClass_IMPL {
 struct NSObject_IMPL NSObject_IVARS;
};
그러나 우 리 는 또 다른 문 제 를 발견 할 것 이다.OC 에서 의 방법 은 이렇게 되 었 다.

//     
_OBJC_$_INSTANCE_METHODS_FunClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
 sizeof(_objc_method),
 1,
 {{(struct objc_selector *)"testInstance", "v16@0:8", (void *)_I_FunClass_testInstance}}
static void _I_FunClass_testInstance(FunClass * self, SEL _cmd) {
}

//    
_OBJC_$_CLASS_METHODS_FunClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
 sizeof(_objc_method),
 1,
 {{(struct objc_selector *)"testClass", "v16@0:8", (void *)_C_FunClass_testClass}}
static void _C_FunClass_testClass(Class self, SEL _cmd) {

}
이 몇 가지 특징 을 발견 했다.
     1.실례 방법 은 다음 과 같다:INSTANCE_METHODS_FunClass,클래스 방법 은 이것 입 니 다:CLASS_METHODS_FunClass
     2,두 가지 방법 모두 static 방법
     3.방법 에 두 개의 인자 가 더 생 겼 습 니 다:self 와cmd,이것 도 왜 self 와cmd 는 방법 중의 근본 적 인 원인 만 있 을 수 있다.
방법 에 관 한 이 부분 은 먼저 여기까지 소개 하고 후기 에는 전문 적 인 주제 가 있 을 것 이다.
4.Class 와 대응 하 는 구조 체 를 사용자 정의 합 니 다.
위 에서 이렇게 많이 말 했 는데,도대체 맞 는 거 야?!그럼 직접 해 보 세 요.
여기 서 사용자 정의 란 NSObject 에 더 이상 계승 되 지 않 고 스스로 구조 체 를 만 드 는 것 을 말한다.그 정확성 을 증명 하기 위해 각각 HGN Object 류 와 HGN Object 를 정의 합 니 다.IMPL 구조 체.작 성 된 코드 는 다음 과 같 습 니 다:

// ====        ====
//     
@interface HGNObject : NSObject {
 @public
 int _no;
 int _age;
}
@end

//     
@implementation HGNObject
@end

// ====     ====
struct HGNObject_IMPL {
 Class isa_hg;
 int _no_hg;
 int _age_hg;
};
두 가지 시험 을 하 다.
1.유전 구조 체
2.구조 체 전환 류
1.유전 구조 체
예제 코드 는 다음 과 같다.

//      
- (void)class2Struct {
 //       
 HGNObject* nObj = [[HGNObject alloc] init];
 //       
 nObj->_no = 771722918;
 nObj->_age = 18;
 
 { //             
 struct HGNObject_IMPL* nObj_s = (__bridge struct HGNObject_IMPL*)nObj;
 //         
 NSLog(@"%zd, %zd", nObj_s->_no_hg, nObj_s->_age_hg);
 //     : 771722918, 18
 }
}
구조 체 지침 을 통 해 클래스 대상 에 설 치 된 값 을 출력 할 수 있 으 며,클래스 전환 구조 체 의 과정 이 유효 하 다 는 것 을 설명 합 니 다.
2.구조 체 전환 류
예제 코드 는 다음 과 같다.

//      
- (void)struct2Class {
 NSLog(@"     ");
 //        
 struct HGNObject_IMPL nObj_s = {0, 771722918, 20};
 //         
 NSLog(@"isa_hg = %zd, _no_hg = %zd, _age_hg = %zd", nObj_s.isa_hg, nObj_s._no_hg, nObj_s._age_hg);
 
 struct HGNObject_IMPL* nObj_sPointer = &nObj_s;
 
 //        
 HGNObject* nObj = (__bridge HGNObject *)(nObj_sPointer);
 
 NSLog(@"_no_hg = %zd, _age_hg = %zd", nObj->_no, nObj->_age);
}
실행 코드,직접 crash:

Block 은 다년간 의 오 해 를 풀 었 다.의 뼈 아 픈 교훈 때문에 만 나 는 crash 에 민감 하 다.위의 이 그림 을 보 세 요.중요 한 점 은 무시 할 수 없 는 것 입 니 다.바로 이곳 의 값 입 니 다.

간단 한 분석.
nObj_s 는 정확 한 값 이 있 습 니 다.nObj 를 설명 합 니 다.sPointer 포인터 도 문제 가 없 는데 왜 나 쁜 주소 로 접근 하 는 지 알 수 있 습 니까?그리고 address 의 값 은 매번 같은 0x 20 입 니 다.나 는 전환 하 는 과정 에서 간단 한 할당 작업 뿐만 아니 라 다른 주소 방문 작업 도 했 을 것 이 라 고 추측 했다.이 조작 은+alloc 방법 에서 조작 하 는 것 과 관련 이 있 을 가능성 이 높다.왜냐하면 OC 에서 정상적으로 대상 을 만 드 는 데 반드시+alloc 방법 이 있어 야 하기 때문이다.+alloc 에서 무슨 일 을 했 는 지 아직 잘 모 르 기 때문에 여 기 는 내 가 받 은 것 이다.여러분,새로운 이해 가 있다 면 가르침 을 바 랍 니 다!
그래서 첫 번 째 실험 에서 의 류 전 구조 체 는 효과 적 이 고 우연 일 수도 있다.왜냐하면 우 리 는 위의.cpp 파일 에서 데이터 구 조 를 볼 때 도 대략적인 것 만 보 았 을 뿐 모든 것 을 보지 못 했다.
OK.이 절(Class 와 대응 하 는 구조 체 를 사용자 정의)에서 만난 불쾌 함 을 잊 어 버 리 고 적어도 유형 전환 구조 체 는 효과 적 이 며 문 제 를 설명 할 수 있 습 니 다.
이 시리즈 의 글 은 다음 과 같다.
1、 Objective-C 클래스 의 데이터 구조
2、 Objective-C 의 인 스 턴 스 가 차지 하 는 메모리 크기
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기