我使用的是特定的API,它有一些类,例如ClassA
。
ClassA
有一个属性importantProperty
,ivar = _importantProperty
,setter = setImportantProperty
我需要的是在属性更改时实际处理调试,以及为此属性设置了什么值并打印堆栈跟踪。
我无法继承此类并在我的情况下覆盖此方法,因为它已定义了类。
所以我创建了一个调试类别,它覆盖了setImportantProperty
方法,现在我可以处理堆栈跟踪和值更改,但是这种方法使得原始方法无法访问,并且无法更改ivar值。有没有办法改变这个伊娃?
这是我的方法:
@implementation ClassA (Test)
-(void) setImportantProperty:(id) newValue {
NSLog(@"%@, %@", newValue, [NSThread callStackSymbols]);
}
@end
所以问题是在我的方法中有没有办法实现这样的代码_importantProperty = newValue
,还是有其他方法可以用在我的案例中?
提前致谢!
答案 0 :(得分:1)
正如@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);
}