我在 NSObject 上有一个类别,它应该包含一些东西。当我在一个对象上调用它时,我想重写它的 dealloc 方法来进行一些清理。
我想使用方法调配来做到这一点,但不知道如何做。我发现的唯一示例是如何替换整个类的方法实现(在我的例子中,它将覆盖所有 NSObject 的 dealloc - 我不想这样做)。
我想重写 NSObject 特定实例的 dealloc 方法。
@interface NSObject(MyCategory)
-(void)test;
@end
@implementation NSObject(MyCategory)
-(void)newDealloc
{
// do some cleanup here
[self dealloc]; // call actual dealloc method
}
-(void)test
{
IMP orig=[self methodForSelector:@selector(dealloc)];
IMP repl=[self methodForSelector:@selector(newDealloc)];
if (...) // 'test' might be called several times, this replacement should happen only on the first call
{
method_exchangeImplementations(..., ...);
}
}
@end
你不能真正做到这一点,因为对象没有自己的方法表。只有类才有方法表,如果更改这些方法表,它将影响该类的每个对象。不过,有一种简单的方法可以解决这个问题:在运行时将对象的类更改为动态创建的子类。这种技术也称为 isa-swizzling,Apple 使用它来实现自动 KVO。
这是一个强大的方法,它有它的用途。但对于您的情况,有一种使用关联对象的更简单的方法。基本上,您使用
objc_setAssociatedObject
将另一个对象关联到第一个对象,该对象在其 dealloc
中进行清理。您可以在这篇关于 Cocoa 是我女朋友的博客文章中找到更多详细信息。
方法选择基于对象实例的class,因此方法调配会影响同一类的所有实例 - 正如您所发现的。
但是你可以改变实例的类,但是你必须小心!这是大纲,假设你有一个课程:
@instance MyPlainObject : NSObject
- (void) doSomething;
@end
现在,如果您只想更改
MyPlainObject
的某些实例,则首先定义一个子类:doSomething
现在您可以清楚地创建
@instance MyFancyObject: MyPlainObject
- (void) doSomething;
@end
的实例,但我们需要做的是获取
MyFancyObject
的 预先存在的 实例并将其放入 MyPlainObject
中,以便我们获得新的行为。为此,我们可以混合类,将以下内容添加到MyFancyObject
:MyFancyObject
现在,对于
static Class myPlainObjectClass;
static Class myFancyObjectClass;
+ (void)initialize
{
myPlainObjectClass = objc_getClass("MyPlainObject");
myFancyObjectClass = objc_getClass("MyFancyObject");
}
+ (void)changeKind:(MyPlainObject *)control fancy:(BOOL)fancy
{
object_setClass(control, fancy ? myFancyObjectClass : myPlainObjectClass);
}
的任何 original 实例,您可以切换为
MyPlainClass
,反之亦然:MyFancyClass
(一些)注意事项:
如果子类重写或添加方法,并添加
MyPlainClass *mpc = [MyPlainClass new];
...
// masquerade as MyFancyClass
[MyFancyClass changeKind:mpc fancy:YES]
... // mpc behaves as a MyFancyClass
// revert to true nature
[MyFancyClass changeKind:mpc: fancy:NO];
(类)变量,您可以仅执行此操作。
您还需要为您希望更改其行为的每个类创建一个子类,您不能拥有一个可以更改许多不同类的行为的类。