1.1.6 스위프트 오브젝티브-C 호환 객체
오브젝티브-C 코드에서 스위프트 객체를 사용하려면 해당 스위프트 객체는 반드시 NSObject를 최상위 클래스로 지정하고 상속받아 만들어야 한다. 그렇지 않으면 스위프트 전용 객체로 동작하기 때문에 오브젝티브-C에서는 사용할 수 없다.
1.2.1 오브젝티브-C 객체와 메모리 구조
오브젝티브-C에서 객체 인스턴스는 항상 힙 영역에 만들어지며, 해당 힙 메모리 주소를 스택 영역에 할당한 포인터로 참조해서 접근한다. 포인터 변수에 담긴 메모리 주소와 해당 주소의 객체 인스턴스가 실제로 유효한지를 포인터 주소만으로는 판단할 수 없다. 객체 포인터 변수는 이미 해제된 객체 주소를 저장하고 있는 위험한 포인터(dangling pointer) 일 수도 있다. 그래서 객체에 대한 참조 개수로 객체 포인터가 유효하도록 보호하는 방식을 활용한다.
1.2.4 객체 예외성
모든 코코아 객체 인스턴스가 힙 영역에 생성되는 것은 아니다. 특이하게도 힙 영역이 아니라 텍스트 영역과 데이터 영역에 생기는 경우도 있다.
NSString
클래스는 NSObject
에서 상속받는 코코아 클래스 중에서 유일하게 전역변수로 선언할 수 있다. 힙 영역이 아니라 텍스트 영역에 “BluePen” 값을 저장하고 aPenName 변수는 전역 변수 형태로 데이터 영역에 만들어진다.
더 특이한 사항은 bPenName 객체처럼 aPenName 변수와 동일한 문자열을 반복해서 사용하는 경우에는 같은 텍스트 영역을 사용하고 해당 객체 인스턴스를 전역 변수 형태로 할당한다는 것이다. 다시 말해 각 변수들은 동일한 정체성을 갖게 된다. 이런 방식을 문자열 인터닝 이라고 부른다.
스위프트에서 String
객체는 네이티브 문자열 객체를 만들 수도 있고, NSString
을 연결해서 쓸 수도 있다. 네이티브 문자열 객체는 내부적으로 인터닝을 시키는 NSString
객체와는 다르게 텍스트 영역에 있는 문자열을 OpaquePointer
형태 포인터로 그대로 연결하는 방식을 사용한다. 따라서 네이티브 문자열 NSString
보다는 좀 더 가벼운 형태라고 할 수 있다.
1.4.2 메시지 디스패치
오브젝티브-C는 객체의 메서드를 직접 호출하지 않고, 스몰토크 언어에서처럼 객체에 메시지를 보내는 방식으로 동작한다.
선언한 클래스로 객체 인스턴스에 메서드를 호출하면, 컴파일하면서 objc_msgSend()
런타임 API를 사용하는 코드로 대체된다.
실행 중에 오브젝티브-C 런타임은 objc_msgSend()
를 실행하면서 메시지로 어떤 메서드를 실행할지 메시지 디스패치 과정을 통해서 찾아낸다.
수신 객체의 클래스 타입과 메시지 셀렉터를 기준으로 어떤 메서드를 실행할지 선택한다. 만약 상속 관계가 있는 경우에는 다형성을 따라 상위 클래스의 메서드를 선택하기도 한다.
이렇게 특정 클래스의 어느 메서드를 실행할지 셀렉터를 고른 후에는, 해당 객체의 메서드 구현부 메모리 주소를 확인해서 메서드를 호출할 준비를 끝낸다. 이렇게 찾은 메모리 주소는 한 번만 쓰고 버리는 것이 아니라 내부 캐시에 저장하고 이후에는 캐시에서 먼저 찾는다.
Uploaded by N2T