18

我在 NSObject 上有一个类别,它应该包含一些东西。当我在一个对象上调用它时,我想重写它的 dealloc 方法来进行一些清理。

我想使用方法调配来做到这一点,但不知道怎么做。我发现的唯一示例是关于如何替换整个类的方法实现(在我的情况下,它将覆盖所有 NSObjects 的 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
4

3 回答 3

20

你不能真正做到这一点,因为对象没有自己的方法表。只有类有方法表,如果您更改它们,它将影响该类的每个对象。但是有一个直接的方法:在运行时将对象的类更改为动态创建的子类。这种技术也称为 isa-swizzling,被 Apple 用于实现自动 KVO。

这是一个强大的方法,它有它的用途。但是对于您的情况,有一种使用关联对象的更简单方法。基本上,您使用objc_setAssociatedObject将另一个对象关联到您的第一个对象,该对象在其dealloc. 您可以在这篇关于 Cocoa is my Girlfriend 的博客文章中找到更多详细信息。

于 2012-02-29T18:34:42.130 回答
12

方法选择基于对象实例的,因此方法调配会影响同一类的所有实例 - 正如您所发现的。

但是你可以改变一个实例的类,但你必须小心!这是大纲,假设你有一堂课:

@instance MyPlainObject : NSObject

- (void) doSomething;

@end

MyPlainObject现在,如果您只想更改某些实例的行为,则doSomething首先定义一个子类:

@instance MyFancyObject: MyPlainObject

- (void) doSomething;

@end

现在您可以清楚地创建 的实例MyFancyObject,但我们需要做的是获取一个预先存在的实例MyPlainObject并将其变为 aMyFancyObject以便我们获得新的行为。为此,我们可以调整类,将以下内容添加到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);
}

现在,对于您的任何原始实例,MyPlainClass您都可以切换为 a 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];

(一些)注意事项:

只有当子类覆盖或添加方法并添加(类)变量时,您才能执行此操作。static

你还需要一个子类来改变你想要改变行为的类,你不能有一个可以改变许多不同类行为的类。

于 2012-02-29T18:38:15.997 回答
1

我制作了一个 swizzling API,它还具有特定于实例的 swizzling。我认为这正是您正在寻找的:https ://github.com/JonasGessner/JGMethodSwizzler

它通过为您在运行时调动的特定实例创建一个动态子类来工作。

于 2013-10-27T22:08:25.370 回答