exchange NSObject#autorelease

昨日までの実験だが、結局のところ NSAutoreleasePool#addObject: を置き換えるのが目的ではない。もともとはコンビニエンスコンストラクタが、オブジェクトを自動解放プールに登録するのかどうかを確認したかったのである。であれば NSAutoreleasePool のサブクラスを作って、それをトップの自動解放プールとするだけで確認できた。

しかし Cocoa Application の中では自動的に自動解放プールが作られるのでそれは無理である。

ということは NSAutoreleasePool#addObject: がだめなら NSObject#autorelease をフックしてみてはどうか。

@interface NSObject (TESTAutoreleasePool)
-(id)TEST_autorelease;
@end

@implementation NSObject (TESTAutoreleasePool)
+(void)load
{
  if (self != [NSObject class])
    return;
  Method originalMethod = class_getInstanceMethod(self, @selector(autorelease));
  Method replaceMethod = class_getInstanceMethod(self, @selector(TEST_autorelease));
  method_exchangeImplementations(originalMethod, replaceMethod);
  NSLog(@"method %s was exchanged with %s\n",
  method_getName(originalMethod), method_getName(replaceMethod));
}

-(id)TEST_autorelease
{
  NSLog(@"exchanged method was called\n");
  NSLog(@"method = %s#%s\n", object_getClassName(self), sel_getName(_cmd));
  return [self TEST_autorelease];
}
@end

int main (int argc, const char * argv[])
{
  NSAutoreleasePool *pool;
  id anObject;

    // --> method autorelease was exchanged with TEST_autorelease
  pool = [[NSAutoreleasePool alloc] init];
  [NSString stringWithUTF8String:"<autorelease>"];
    // --> exchanged method was called
    //     method = NSCFString#autorelease
  [[[NSObject alloc] init] autorelease];
    // --> exchanged method was called
    //     method = NSObject#autorelease
  anObject = [[NSObject alloc] init];
  [pool addObject:anObject];  // 何も出力されない
  [pool drain];
  return 0;
} 

期待通り autorelease をフックできたようだ。