调整单个实例,而不是类

Gil*_*vik 17 methods objective-c categories swizzling ios

我在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
Run Code Online (Sandbox Code Playgroud)

Sve*_*ven 19

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

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


CRD*_*CRD 10

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

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

@instance MyPlainObject : NSObject

- (void) doSomething;

@end
Run Code Online (Sandbox Code Playgroud)

现在,如果只是MyPlainObject为了改变doSomething你的行为的某些实例,首先要定义一个子类:

@instance MyFancyObject: MyPlainObject

- (void) doSomething;

@end
Run Code Online (Sandbox Code Playgroud)

现在你可以清楚地创建实例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);
}
Run Code Online (Sandbox Code Playgroud)

现在,对于任何原始实例,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];
Run Code Online (Sandbox Code Playgroud)

(一些)警告:

你可以只有做到这一点,如果子类覆盖或添加方法,并增加了static(类)变量.

你还需要一个你希望改变行为的类的子类,你不能拥有一个可以改变许多不同类的行为的类.