isa (런타임 내부 동작 과정)

Tags
messaging
deprecated

메세징 기법 요약

  • obj-c는 다른 객체지향 언어와 달리 메세징 기법을 사용한다.
  • 코드 작성 시에는 메세지 전달 구분을 작성하고,
  • 빌드 후 실행시키면 런타임 라이브러리 함수들을 이용해 메세지 처리부분을 찾아가서 실행시킨다.

isa

참고링크
실제 런타임 시에 메세지 처리 함수를 어떻게 찾아갈까?
  • 모든 객체들은 isa 라고하는 멤버변수를 갖고 있다.
  • isa는 객체를 생성한 클래스 오브젝트를 가리키는 포인터 변수다.
//클래스 오브젝트 포인터를 Class로 typedef typedef struct objc_class *Class; //오브젝트는 자신을 할당한 클래스 오브젝트에 대한 포인터 변수를 가짐 (isa) typedef struct objc_object { Class isa; } *id;
 

클래스 오브젝트?

인스턴스 오브젝트 vs 클래스 오브젝트
  • 오브젝트에는 해당 오브젝트를 할당한 클래스 오브젝트의 주소를 담는 포인터 변수 isa가 있다고 했다.
  • 클래스면 클래스지 클래스 오브젝트는 또 뭘까?
  • Obj-c에는 클래스의 인스턴스 뿐만 아니라, 클래스 자체도 하나의 오브젝트로 존재한다.
 
지금까지 인스턴스 오브젝트 할당 시 당연하게도 [클래스명 alloc]라는 메세지 구문으로 할당했는데, 클래스명이라고 적었던 것이 사실은 클래스 오브젝트에 메세지를 전달하는 것을 알고나면 이해가 된다.
RacingCar *firstCar = [[RacingCar alloc] init]; RacingCar *secondCar = [[RacigCar alloc] init];
  • 클래스 오브젝트alloc 메세지를 보내면 객체를 할당한 뒤 isa 멤버변수에 오브젝트를 할당한 자기자신 즉, 클래스 오브젝트의 주소를 담고 반환한다.
 
[firstCar pitIn];
  • 다음은 할당된 인스턴스 오브젝트에 메세지를 보내는 구문이다.
  • 해당 구문은 런타임에 인스턴스 오브젝트isa를 통해 클래스 오브젝트를 얻고, 클래스 오브젝트의 디스패치 테이블을 참조하여 셀렉터에 대응하는 함수를 찾아서 호출하게 된다.
 

디스패치 테이블

클래스 오브젝트에서 셀렉터에 대응하는 함수 주소를 어떻게 찾을까?
  • 클래스 오브젝트는 해당 클래스가 구현하는 모든 메소드의 정보를 가지고 있고, 이것을 Dispatch table이라고 한다.
 
  1. 인스턴스 오브젝트가 메세지를 호출하면 isa를 통해 클래스 오브젝트를 얻는다.
  1. 클래스 오브젝트의 디스패치 테이블에서 셀렉터에 대응하는 메소드를 찾는다.
  1. 대응하는 메소드를 찾지 못했으면 superclass의 디스패치 테이블을 본다. (상속받은 클래스 참조)
  1. 2~3 반복.
  1. 찾지못하고 루트 클래스 오브젝트에 도달하면 대응하지 못한다고 판단하고 이에 맞는 런타임 함수를 호출.
 
notion image
 

루트 클래스

어떠한 클래스도 상속받지 않는 최상위 클래스를 루트 클래스라고 한다.
코코아 프로그래밍 환경에서 루트 클래스는 항상 NSObject 혹은 NSProxy다. (대부분 NSObject를 상속)
루트 클래스인 NSObject 클래스NSObject 프로토콜을 채택하므로 프로토콜에 명시된 메소드는 반드시 구현되어야 한다.
 

메타 클래스

클래스 오브젝트도 하나의 오브젝트이므로 역시 자신을 생성한 클래스 오브젝트의 주소를 담는 isa를 갖는다.
  • 클래스 오브젝트를 생성하는 클래스 오브젝트를 메타클래스 오브젝트라고 한다.
  • 모든 메타클래스 오브젝트의 isa루트 클래스의 '메타클래스 오브젝트'를 가리킨다.
    • (루트 메타클래스 오브젝트 자신도 포함)
 

결론

지금까지의 내용을 종합해보면 인스턴스 오브젝트, 클래스 오브젝트, 메타클래스 오브젝트와의 관계는 아래 그림과 같이 정리할 수 있다.
notion image