Objective-C Runtime Programming Guide 요약 자료입니다.
Objective-C 런타임을 사용하면 성능을 향상 시킬수 있는 기법을 사용할 수 있습니다.
동적 바인딩이 속도면에서는 접고 들어가는거라 런타임 기능을 이해하면 좀 더 향상된 앱을 개발할 수 있지 않을까 합니다~~
일부 다른 자료 참고했고, 이미지도 이모씨!!의 자료 사용했습니다~ㅋ
2. ✓ Objective-C 언어는 runtime 시에 많은 결정을 함.
✓ 컴파일된 코드를 실행하기 위해서는 컴파일러 뿐만
아니라 Runtime System이 필요함.
✓ Runtime System은 일종의 OS와 같이 동작.
- Objective-C 프로그램이 어떻게 runtime system과 상호작용하는지.
- 런타임시에 새로은 클래스를 어떻게 동적으로 로딩하는지.
- 다른 객체에게 어떻게 메시지를 전달하는지.
- 프로그램이 실행중인 동안 어떻게 객체에 대한 정보를 찾는지.
13년 5월 21일 화
3. Interacting with the Runtime
Objective-C 프로그램은 3가지 레벨에서 런타임 시스템과 상호작용
1. Objective-C Source Code
2. NSObject Methods
3. Runtime Functions
13년 5월 21일 화
4. ClassC의 객체
obj isa
stack Heap
Code
ClassC
-methodC
super
ClassB
-methodB
ClassA
super
-methodA
NSObject
super
NSNumber
-methodX +alloc
NSNumber의 객체
num
isa
super
-init -init
+alloc
객체 생성 과정
13년 5월 21일 화
5. Interacting with the Runtime
1. Objective-C Source Code
✓ 런타임 시스템의 동작은 보이지 않는 곳에서 자동으로 동작
✓ Objective-C 소스코드를 작성하고 컴파일하게 되면 런타임 시스템을 간접적으로
사용
✓ 코드를 컴파일 하게 되면 data structure와 언어의 동적인 특성을 구현한 함수
호출을 만들어 냄
✓ Data Structure
- Class와 Category 정의, Protocol 선언 정보
- method selector, instance variable templates, 그리고 소스 코드에서 추출된
다른 정보 등
13년 5월 21일 화
6. Interacting with the Runtime
2. NSObject Methods
✓ Cocoa에서 대부분의 객체는 NSObject 클래스의 서브클래스
✓ 몇몇 메소드는 런타임 시스템에 간단한 질의 수행
- 객체가 자신의 내부 정보를 획득(introspection)
- class
- isKindOfClass: , isMemberOfClass
- respondsToSelectors:
- conformsToProtocol:
- methodForSelectors:
13년 5월 21일 화
7. Interacting with the Runtime
3. Runtime Functions
✓ /usr/include/objc 에 있는 헤더 파일내의 데이터 구조나 함수의 조합
✓ 순수 C로 작성
✓ Objective-C 프로그래밍에는 필요하지 않음
✓ 런타임 시스템 인터페이스를 개발할 때 사용
13년 5월 21일 화
8. Messaging
Objective-C에서 메시지는 런타임까지 구현부에 바인딩 되지 않는다.
[receiver message] objc_msgSend(receiver, selector)
objc_msgSend(receiver, selector, arg1, arg2, ...)
✓ objc_msgSend(messaging function) 함수가 동적 바인딩에 필요한
모든 것을 수행.
- selector가 참조하는 procedure(method implementation)를 찾는다.
- 같은 함수가 다른 클래스에서 다르게 구현되어 있을 수 있기 때문에 정확한
procedure를 찾는 것은 receiver의 클래스에 달려있다.
- receiving object에 데이터 포인터 전달, procedure 호출.
- 처리 값 반환
✓ objc_msgSend 함수를 코드에서 직접 호출하면 안 됨!
13년 5월 21일 화
9. Messaging
‣ 모든 클래스 객체는 다음 두 가지 항목을 포함하고 있다.
✓ superclass에 대한 포인터
✓ class dispatch table
- selector와 함수 구현부의 주소를 연결
‣ 새로운 객체가 생성될 때 할당된 메모리와 인스턴스 변수들 초기화
‣ 객체의 변수들 중 첫번째는 클래스 구조에 대한 포인터
- isa 라고 부르를 포인터
- 클래스 자체와 클래스가 상속받은 모든 클래스에 대한 접근이 가능
- isa 포인터는 언어의 일부분이 아니지만, 런타임 시스템에서 동작하기 위해 필요
13년 5월 21일 화
10. Messaging
함수가 동적으로 메소드에 바인딩
되는 과정
메시지가 객체에 전달
isa 포인터를 참조
dispatch table 검색
superclass 포인터를 참조
dispatch table 검색
cache 검색(MRU)
13년 5월 21일 화
11. Using Hidden Arguments
✓ objc_msgSend가 procedure를 찾으면 호출하고, 메시지 내의 모든 인자를 전달
✓ 두개의 숨은 인자
- receiver
- selector
✓ 메소드를 정의한 코드에 선언되어 있지 않기 때문에 “hidden argument”
✓ 코드가 컴파일 될 때 삽입
✓ 메소드는 수신 객체를 self로, 자신에 대한 selector를 _cmd로 참조
13년 5월 21일 화
13. Getting a Method Address
✓ 동적 바인딩을 회피하는 유일한 방법은 메소드의 주소를 얻어서 마치 함수인 것
처럼 직업 호출하는 방법
- 특정 메소드가 많은 횟수 반복적으로 사용될 때 매번 메시징 하는 오버헤드를 피하고 싶을 때
사용
✓ NSObject 클래스에 정의된 methodForSelector 사용
- procedure의 포인터 조회
- 포인터를 사용하여 procedure 호출
- 포인터는 알맞은 함수 타입으로 형변환 해야 함!
void (*setter)(id, SEL, BOOL);
int i;
setter = (void (*)(id, SEL, BOOL))[target methodForSelector:@selector(setFilled:)];
for ( i = 0; i < 1000; i++ )
setter(targetList[i], @selector(setFilled:), YES);
13년 5월 21일 화
14. Getting a Method Address
@interface MyClass : NSObject {
}
-(void)doSomething;
@end
@implementation MyClass
-(void) doSomething {
// Do many many work
}
@end
MyClass* myObject = [ [ MyClass alloc ] init ] ;
SEL method = @selector(doSomething) ;
IMP func = [ myObject methodForSelector:method ] ;
func( myObject, method );
13년 5월 21일 화
15. Dynamic Method Resolution
✓ 동적으로 메소드를 제공해야할 경우가 종종 있다.(?)
- @dynamic propertyName;
- resolveInstanceMethod:
- resolveClassMethod:
- 주어진 selector에 대한 구현을 동적으로 제공
✓ Objective-C 메소드는 최소한 두개의 인자(self, _cmd)를 갖는 C 함수
✓ class_addMethod 함수를 사용하여 클래스에 함수를 메소드로 추가할 수 있음.
✓ Forwarding 메소드 또는 dynamic method resolution 둘 중 한가지 방법으로
동적 메소드 호출
✓ Forwarding 메커니즘을 시작하기 전에 dynamic method resolution 을 수행
13년 5월 21일 화
16. Dynamic Method Resolution
void dynamicMethodMP(id self, SEL _cmd) {
// implementation …
}
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
if (aSEL == @selector(resolveThisMethodDynamically)) {
class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP,“v@:”);
returnYES;
}
return [super resolveInstanceMethod:aSEL];
}
@end
13년 5월 21일 화
18. Message Forwarding
✓ 메시지 처리가 정의되어 있지 않은 객체에 메시지를 보내면 에러 발생
✓ 에러가 발생하기 전에 런타임 시스템은 메시지를 이해하고 있는 곳으로 메시지를
전달
==> Message Forwarding
✓ NSInvocation 객체를 단일 인자로 하는 forwardInvocation 메시지 전달
-(void)forwardInvocation:(NSInvocation *) anInvocation
✓ 이 메소드는 NSObject에서 정의되어 있기 때문에 모든 객체에 사용할 수 있음.
✓ NSInvocation객체에는 target, selector, parameter 같이 메세지 송신에 필요한 모든
정보가 들어있음.
13년 5월 21일 화
19. Message Forwarding
- negotiate {
if ( [someOtherObject respondsTo:@selector(negotiate)] )
return [someOtherObject negotiate];
return self;
}
13년 5월 21일 화
20. Message Forwarding
- (void)forwardInvocation:(NSInvocation *)anInvocation {
if ([someOtherObject respondsToSelector: [anInvocation selector]])
[anInvocation invokeWithTarget:someOtherObject];
else
[super forwardInvocation:anInvocation];
}
- 동적인 방법으로 메시지 전달
- 메시지 내의 selector와 일치하는 메소드가 없을 때 호출
- 원래 인자들과 함께 전달할 곳으로 보내야 함
- 전달된 메시지의 리턴값은 원래 호출자에게 돌아감
- 알 수 없는 메시지들을 서로 다른 수신자에게 배분하는 역할
(또는 모든 메시지를 같은 목적지로 보내는 역할)
- 객체에 전달한 메시지가 존재할 경우 forwardInvocation은 호출되지 않음
13년 5월 21일 화
21. Forwarding and Multiple Inheritance
✓ 포워딩은 다중 상속의 효과를 주는데 사용할 수 있다.
(다중 상속에서 원하는 대부분의 기능을 제공)
✓ 메시지를 전달하는 객체는 receiver가 메시지를 처리하는 것 처럼 보이며,
값을 리턴 받는다.
13년 5월 21일 화
22. Surrogate Object
✓ 다른 객체를 대신하고 메시지를 전달해주는 역할
✓ 크고, 무거운 동작을 수행하는 객체의 앞단에서 동작하는 객체
(경량 객체)
✓ 데이터에 관한 질의와 같은 간단한 처리는 직접 수행하고, 무거운 처리가 필요할
경우 실제 처리 객체에게 메시지 전달
✓ 커다란 객체로 향하는 모든 메시지는 surrogate를 통하게 되고, 다른 객체들은 두
객체를 동일하게 보게 됨
13년 5월 21일 화
23. Forwarding and Inheritance
✓ 포워딩이 상속과 유사하게 보일지라도, respondsToSelector: , isKindOfClass: 같은
메소드는 forwarding chain을 고려하지 않는다.
✓ 만약 포워딩 객체가 실제 객체의 모든 행위를 상속 받은 것 처럼 사용하고 싶다면,
위 메소드를 오버라이딩 해야 한다.
(BOOL)respondsToSelector:(SEL)aSelector
{
if ( [super respondsToSelector:aSelector] ) returnYES;
else { /* 이 부분에 aSelector 메시지가 *
* 다른 객체로 전달될 수 있는지 그리고 *
* 해당 객체가 메시지에 응답할 수 있는지를 체크하고 *
* 그럴수 있다면YES를 되돌리는 코드를 넣는다. */
}
return NO;
}
13년 5월 21일 화
24. Forwarding and Inheritance
✓ instancesRespondToSelector: , conformsToProtocol: 메소드 등도 필요에 따라
반영해야 한다.
✓ 객체가 원격지에서 수신한 모든 메시지를 전달한다면,
methodSignatureForSelector: 메소드 구현해야 한다.
(NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
NSMethodSignature* signature = [super methodSignatureForSelector:selector];
if (!signature) {
signature = [surrogate methodSignatureForSelector:selector];
}
return signature;
}
13년 5월 21일 화