이런 거를 Hooking이라고 표현해도 되는지 잘 모르겠다만...
가끔씩 카테고리를 사용해서 기존의 메소드를 덮어쓰는게 아니라 기존의 메소드를 그냥 놔두고 나의 코드를 삽입하고 싶은 경우가 있을 수 있다. LD_PRELOAD를 이용해서 원래 함수의 실행을 가로막고 뭔가 할 수 있는 것처럼...
Objective-C Runtime API를 이용하면 가능하다. 원리는 기존 메소드를 다른 이름으로 복사하고 새로운 메소드를 같은 이름으로 추가하는 것이다. 그러면 새로운 메소드에서 필요시 기존 메소드를 호출할 수 있다.
다음 예제는 NSView의 -addSubview: 메소드앞단에 로그찍는 코드를 끼워넣은 것이다.
#import <objc/runtime.h>
@implementation NSView (Logging)
static void addSubviewLogging(id self, SEL _cmd, NSView *aView)
{
NSLog(@"-[%@ addSubview:%@]", self, aView);
[self addSubviewReal:aView];
}
+ (void)load
{
class_addMethod(self, @selector(addSubviewReal:), [self instanceMethodForSelector:@selector(addSubview:), "v@:@");
class_replaceMethod(self, @selector(addSubview:), (IMP)addSubviewLogging, "v@:@");
}
@end
이 코드는 단지 예제일 뿐... 응용은 알아서...
이 글은 스프링노트에서 작성되었습니다.
환경변수 NSObjCMessageLoggingEnabled를 YES로 세팅하고 코코아 응용프로그램을 실행하면 응용프로그램에서 발생하는 모든 Objective-C 메세징을 로그파일에 써준다. 로그파일은 /tmp/msgSends-PID.
하지만, 이거는 도움이 될 수가 없다. 워낙 많은 메세징이 발생하기 때문... 원하는 것은 특정 부분에서 어떤 메세징이 발생하는지가 될 것이다.
소스코드상에서 다음과 같이 관심있는 부분 앞뒤로 메세지 로깅을 켜고 끌 수 있다.
instrumentObjcMessageSends(YES); /* 메세징 로깅을 원하는 코드 */ instrumentObjcMessageSends(NO);
이 글은 스프링노트에서 작성되었습니다.
환경변수 OBJC_HELP를 1로 세팅하고 파운데이션 프로그램을 실행시키니 이런 것이 나오네...
도움이 될 만한 것이 있을지도...
objc[31709]: OBJC_HELP: describe Objective-C runtime environment variables objc[31709]: OBJC_PRINT_OPTIONS: list which options are set objc[31709]: OBJC_PRINT_IMAGES: log image and library names as they are loaded objc[31709]: OBJC_PRINT_LOAD_METHODS: log calls to class and category +load methods objc[31709]: OBJC_PRINT_INITIALIZE_METHODS: log calls to class +initialize methods objc[31709]: OBJC_PRINT_RESOLVED_METHODS: log methods created by +resolveClassMethod: and +resolveInstanceMethod: objc[31709]: OBJC_PRINT_CLASS_SETUP: log progress of class and category setup objc[31709]: OBJC_PRINT_PROTOCOL_SETUP: log progresso of protocol setup objc[31709]: OBJC_PRINT_IVAR_SETUP: log processing of non-fragile ivars objc[31709]: OBJC_PRINT_FUTURE_CLASSES: log use of future classes for toll-free bridging objc[31709]: OBJC_PRINT_RTP: log initialization of the Objective-C runtime pages objc[31709]: OBJC_PRINT_GC: log some GC operations objc[31709]: OBJC_PRINT_SHARING: log cross-process memory sharing objc[31709]: OBJC_PRINT_CXX_CTORS: log calls to C++ ctors and dtors for instance variables objc[31709]: OBJC_PRINT_EXCEPTIONS: log exception handling objc[31709]: OBJC_PRINT_ALT_HANDLERS: log processing of exception alt handlers objc[31709]: OBJC_PRINT_REPLACED_METHODS: log methods replaced by category implementations objc[31709]: OBJC_PRINT_DEPRECATION_WARNINGS: warn about calls to deprecated runtime functions objc[31709]: OBJC_PRINT_CACHE_COLLECTION: log cleanup of stale method caches objc[31709]: OBJC_DEBUG_UNLOAD: warn about poorly-behaving bundles when unloaded objc[31709]: OBJC_DEBUG_FRAGILE_SUPERCLASSES: warn about subclasses that may have been broken by subsequent changes to superclasses objc[31709]: OBJC_DEBUG_FINALIZERS: warn about classes that implement -dealloc but not -finalize objc[31709]: OBJC_DEBUG_NIL_SYNC: warn about @synchronized(nil), which does no synchronization objc[31709]: OBJC_USE_INTERNAL_ZONE: allocate runtime data in a dedicated malloc zone objc[31709]: OBJC_ALLOW_INTERPOSING: allow function interposing of objc_msgSend() objc[31709]: OBJC_DISABLE_GC: force GC OFF, even if the executable wants it on
이 글은 스프링노트에서 작성되었습니다.


