objc_object 、objc_class、metaclass

[0] Outline
-- [1] id 및 Class
-- [2] 클래스를 동적으로 조작
-- [3] 실례화
[1] id 및 Class
Objective-C에 특별한 데이터 형식이 대상 식별자입니다: id. 모든 종류의 대상을 가리킬 수 있습니다.
'어떤 유형의 대상을 가리킬 수 있다'는 설명을 통해 id는 실제적으로 Objective-C 대상 시스템의 기본 클래스(계승 시스템의 조상 구조)를 가리키는 지침이고 실행할 때 대상 메모리 레이아웃의 기본 클래스 부분을 가리킨다고 추측할 수 있다.
처음 id 데이터 형식을 보았을 때 나는 파이톤의 PyObject 구조를 연상했다.
[cpp]  view plain copy
typedef struct _object {  
    int ob_refcnt;  
    struct _typeobject *ob_type;  
} PyObject;  
이 데이터 형식도 Python 대상 시스템의 조상 유형이지만 id와 대응하는 것은 PyObject* 유형이어야 한다.
id 데이터 형식은 struct objc 를 가리킵니다.object 구조에 대한 포인터:
[cpp]  view plain copy
typedef struct objc_class *Class;  
typedef struct objc_object {  
    Class isa;  
} *id;  
더 정확히 말하면 id는 Class 유형을 가리키는 지침이고 Class는 struct objc 를 가리킨다class 구조에 대한 포인터:
[cpp]  view plain copy
struct objc_class {  
     struct objc_class *isa;  
  
     struct objc_class *super_class;   
     const char *name;    
     long version;  
     long info;  
     long instance_size;  
     struct objc_ivar_list *ivars;  
     struct objc_method_list **methodLists;  
     struct objc_cache *cache;  
     struct objc_protocol_list *protocols;  
};  
그러면 Objective-C 객체 시스템의 초석을 볼 수 있습니다:struct objcclass 구조:
[cpp]  view plain copy
isa 포인터: 객체가 속한 유형의 유형 객체(Class Object)를 가리킵니다.Objective-C에서 클래스도 대상으로 표시되고, 클래스의isa 바늘은 메타클래스를 가리킨다. (정적 구성원 변수와 클래스 방법을 저장한다.)  
super_class 포인터: 부모 클래스를 가리킵니다.  
name: 클래스 이름.  
version: 클래스의 버전 정보입니다.  
info: 런타임에 사용되는 플래그 비트(예: 0x1(CLS CLASS)는 클래스가 일반 클래스이고 0x2(CLS META)는 클래스가 metaclass임을 나타냅니다.  
instance_크기: 실례 크기, 즉 메모리가 차지하는 공간입니다.  
ivars: 구성원 변수 목록을 가리키는 바늘입니다.  
methodLists: 로고 위치에 따라 지향이 다를 수 있습니다. 예를 들어 실례 방법 목록을 가리키거나 클래스 방법 목록을 가리킬 수 있습니다.  
cache: Objective-C의 메시지 전송은 디스패치 테이블을 찾아야 하고 계승 시스템을 옮겨다닐 수도 있기 때문에 캐시가 최근에 사용한 방법입니다.  
protocols: 클래스가 준수해야 하는 프로토콜입니다.  
[2] 동적 조작 클래스
클래스도 하나의 대상이라는 것을 알았기 때문에 클래스 대상도 하나의 유형이 있다. 이런 유형은 클래스의 메타클래스이다. 따라서 클래스 방법은 사실 메타클래스의 구성원 방법이고 클래스와 메타클래스는 조립되어 나타난다.
그러면 메타클래스의 이사 포인터와 슈퍼class 바늘이 어떻게 가리키죠?
만약metaclass가 기본 클래스에 대응한다면, 그것의isa는 자신, 슈퍼 를 가리킨다class 바늘은 대응하는 클래스 (기본 클래스) 를 가리킨다.그렇지 않으면 isa 포인터가 기본 클래스의 metaclass, 슈퍼 를 가리킨다class 바늘은 부모 클래스의metaclass를 가리킨다.
기본 isa 지침은nil입니다.
이는 파이톤에서 유사한 디자인 사상을 떠올리게 한다. 예를 들어 정형 숫자 2의 유형은 PyIntObject이고 PyIntObject류의 유형은 PyTypeObject이며 PyTypeObject의 유형은 PyTypeObject이다.여기서 끝난다.
마찬가지로 파이톤에도 메타클라스가 존재한다.
클래스의 표시 구조를 알게 되면 우리는 동태적으로 클래스를 조작하고 깊이 이해할 수 있다.
#import <UIKit/UIKit.h>
#import <objc/objc.h>
#import <objc/runtime.h>
#import "AppDelegate.h"

void selfIntro(id self, SEL _cmd);

int main(int argc, char *argv[])
{
    @autoreleasepool {
        /*
                ,    objc_allocateClassPair  。
                    ,     class_addMethod  class_addIvar。
                ,  objc_registerClassPair。           。
         */
        /*
              :       ,  Nil         。
              :     
              :   0
         */
        //  NSDemo    NSObject
        Class demoClass = objc_allocateClassPair([NSObject class], "NSDemo", 0);
        BOOL isOk = NO;
        
        /*
               
              : 
              :   SEL
              :SEL     
                 ,             ,            ,      ,               method_setImplementation
         */
        // methodLists      
        //"v@:" indicates the function type : v - void, @ - object, : - SEL
        isOk = class_addMethod(demoClass, @selector(intro), (IMP)&selfIntro, "v@:");
        isOk == YES ? nil : NSLog(@"failed on class_addMethod
"); /* : metaclass : :sizeof(id) :log2(sizeof(id)) */ // ivars isOk = class_addIvar(demoClass,"myVar", sizeof(id), log2(sizeof(id)), "@"); isOk == YES ? nil : NSLog(@"failed on class_addIvar
"); // objc_allocateClassPair objc_registerClassPair(demoClass); // id demo = class_createInstance(demoClass, 0); if ([demo respondsToSelector:@selector(intro)]) { [demo performSelector:@selector(intro)]; } // object_setInstanceVariable(demo, "myVar", nil); void *outValue = (void *)0x1; // /* : , */ object_getInstanceVariable(demo, "myVar", &outValue); if (nil == outValue) { NSLog(@"Hello,nil
"); //printed } // 。 object_dispose(demo); return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } void selfIntro(id self, SEL _cmd) { NSLog(@"self: %@ -- _cmd: %s",self,_cmd); Class isa = object_getClass(self); while (1) { if (isa == isa->isa) { //Finally, NSObject's metaclass points to itself NSLog(@"== : %p, %@", isa, objc_getMetaClass(class_getName([isa class]))); break; } NSLog(@"!= : %p, %@", isa, objc_getMetaClass(class_getName([isa class]))); isa = isa->isa; //Then, isa is assigned to NSDemo's metaclass } }
2014-01-29 11:21:08.912 Caipiao[4593:610132] self: <NSDemo: 0x7fb44bc0a7d0> -- _cmd: intro
2014-01-29 11:21:08.923 Caipiao[4593:610132] != : 0x7fb44bc0a5b0, NSDemo
2014-01-29 11:21:08.927 Caipiao[4593:610132] != : 0x7fb44bc0a5e0, NSDemo
2014-01-29 11:21:08.933 Caipiao[4593:610132] == : 0x10b725d50, NSObject
2014-01-29 11:21:08.934 Caipiao[4593:610132] Hello,nil

[3] 실례화
하나의 대상을 실례화하려면 클래스의 정의에 따라 진행해야 한다.클래스의 정의는 클래스 이름, 데이터, 조작 데이터의 방법을 포함한다.
컴파일링 과정은 클래스의 정보를 기록하여runtime system에 사용할 수 있으며, 컴파일러는 클래스마다 유일한 대상을 만들어서class object를 표시합니다.기능적으로 말하자면,class object도factory object이며, 클래스 방법을 실행할 수 있으며, 실례를 만드는 것을 책임진다.
이런 측면에서 볼 때, 나는class object가metaclass인지 아닌지를 생각하고 있지만, 확인할 수 없다.
Apple 공식 문서인 TOCPL에는 "a class object keeps the prototype of a class instance"라는 문장이 있지만, metaclass는 실례의 원형이 될 수 없습니다.
그래서 나는classobject가 실행될 때class와metaclass가 결합된 제한된 표현이라고 생각한다. 컴파일러가 포착한 클래스 정보에 접근할 수 있고 구성원 변수가 없으면 구성원 방법을 호출할 수 없지만 클래스 방법을 실행할 수 있다.
소스 계층에서 보면 class object는 다음 코드와 같이 클래스 이름으로 표시됩니다.
[cpp]  view plain copy
int version = [NSString version];  
NSString은 class object를 나타냅니다.
우선,class object는runtime 시스템에 의해 initialize 메시지를 보내서 실행할 때의 준비를 초기화합니다. 예를 들어 정적 변수를 초기화하는 것입니다.
이후,class object 방법 (클래스 방법) alloc를 호출하여 새로운 실례 대상에게 메모리 공간을 분배하고, 모든 변수를 0으로 초기화하며,isa 바늘은 소속 클래스를 가리킨다.
마지막으로 init 함수를 호출해서 필요한 초기화를 진행합니다.
여기까지 썼는데 갑자기 사무실 위치를 바꾸려고 해서 생각이 끊겨서 여기까지 썼어요.
마지막으로 SO에서 본 질문을 하나 남겨두면 저도 의심스럽습니다. 몇 가지 추측만 할 수 있습니다.http://stackoverflow.com/questions/8847146/whats-is-methodlists-attribute-of-the-structure-objc-class-for
[이 글은 SO의 질문에 대한 나의 대답이다.http://blog.csdn.net/jasonblog/article/details/7303618]

좋은 웹페이지 즐겨찾기