Swizzling a single instance, not a class

前端 未结 3 1970
我寻月下人不归
我寻月下人不归 2021-02-04 04:05

I have a category on NSObject which supposed to so some stuff. When I call it on an object, I would like to override its dealloc method to do some cleanups.

I wanted to

3条回答
  •  长情又很酷
    2021-02-04 04:48

    Method selection is based on the class of an object instance, so method swizzling affects all instances of the same class - as you discovered.

    But you can change the class of an instance, but you must be careful! Here is the outline, assume you have a class:

    @instance MyPlainObject : NSObject
    
    - (void) doSomething;
    
    @end
    

    Now if for just some of the instances of MyPlainObject you'd like to alter the behaviour of doSomething you first define a subclass:

    @instance MyFancyObject: MyPlainObject
    
    - (void) doSomething;
    
    @end
    

    Now you can clearly make instances of MyFancyObject, but what we need to do is take a pre-existing instance of MyPlainObject and make it into a MyFancyObject so we get the new behaviour. For that we can swizzle the class, add the following to 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);
    }
    

    Now for any original instance of MyPlainClass you can switch to behave as a MyFancyClass, and vice-versa:

    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];
    

    (Some) of the caveats:

    You can only do this if the subclass overrides or adds methods, and adds static (class) variables.

    You also need a sub-class for ever class you wish to change the behaviour of, you can't have a single class which can change the behaviour of many different classes.

提交回复
热议问题