@vikingosegundo が示唆したように、メソッドのスウィズリングを使用できます。
#import "ClassA+Test.h"
#import <objc/runtime.h> // Needed for method swizzling
@implementation ClassA(Test)
-(void) swizzled_setImportantProperty:(id) newValue {
[self swizzled_setImportantProperty: newValue]; //it is NOT an endless recursion.
NSLog(@"%@, %@", newValue, [NSThread callStackSymbols]);
}
+(void)load
{
Method original, swizzled;
original = class_getInstanceMethod(self, @selector(setImportantProperty:));
swizzled = class_getInstanceMethod(self, @selector(swizzled_setImportantProperty:)); //UPDATE: missed a column here, sorry!
method_exchangeImplementations(original, swizzled);
}
@end
ここで新しいメソッドを宣言し、swizzled_setImportantProperty:
実行時にその実装を実装と交換しますsetImportantProperty:
。setImportantProperty:
そのため、コードを呼び出すと、の実装swizzled_setImportantProperty
が呼び出され、その逆も同様です。
そのためswizzled_setImportantProperty:
、実装内で呼び出すと、実装が呼び出されるswizzled_setImportantProperty:
ため、無限再帰は呼び出されませんsetImportantProperty:
。必要なものだけです。
更新:+load
メソッドが既に実装されている場合(またはライブラリ作成者によって将来実装される可能性がある場合)、メソッドをオーバーライドすると問題が発生する可能性があるため、 @ JoshCaswell によって提案されたより良いオプションがあります:
#import "ClassA+Test.h"
#import <objc/runtime.h> // Needed for method swizzling
@implementation ClassA(Test)
-(void) swizzled_setImportantProperty:(id) newValue {
[self swizzled_setImportantProperty: newValue]; //it is NOT an endless recursion.
NSLog(@"%@, %@", newValue, [NSThread callStackSymbols]);
}
@end
void swizzleSetImportantProperty(void) __attribute__((constructor))
{
Method original, swizzled;
original = class_getInstanceMethod([ClassA class], @selector(setImportantProperty:));
swizzled = class_getInstanceMethod([ClassA class], @selector(swizzled_setImportantProperty:)); //UPDATE: missed a column here, sorry!
method_exchangeImplementations(original, swizzled);
}