Objective-C: How to change the class of an object at runtime?

后端 未结 2 1700
庸人自扰
庸人自扰 2020-12-01 11:57

I tried to answer Using a UITableView subclass with a UITableViewController with ISA Switching like so:

self.tableView->isa = [MyTableView class];
         


        
相关标签:
2条回答
  • 2020-12-01 11:58

    The safe way is to create a new instance.

    Swapping isa is not safe - you have no idea what the memory layout of a class is or what it will be in the future. Even moving up the inheritance graph is really not safe because objects' initialization and destruction would not be performed correctly - leaving your object in a potentially invalid state (which could bring your whole program down).

    0 讨论(0)
  • 2020-12-01 12:09

    If your tableview class provides ANY storage this will break. I would not recommend the path you're going down. But the correct method would be to use object_setClass(tableView, [MyTableView class]).

    Please make sure this is really what you want.

    Here is a small code-sample showing how this is a horrible idea.

    #import <objc/runtime.h>
    
    @interface BaseClass : NSObject
    {
        int a;
        int b;
    }
    @end
    
    @implementation BaseClass
    
    @end
    
    @interface PlainSubclass : BaseClass
    @end
    
    @implementation PlainSubclass
    @end
    
    @interface StorageSubclass : BaseClass
    {
    @public
        int c;
    }
    @end
    
    @implementation StorageSubclass
    @end
    
    
    
    int main(int argc, char *argv[])
    {
        BaseClass *base = [[BaseClass alloc] init];
        int * random = (int*)malloc(sizeof(int));
        NSLog(@"%@", base);
    
        object_setClass(base, [PlainSubclass class]);
        NSLog(@"%@", base);
    
        object_setClass(base, [StorageSubclass class]);
        NSLog(@"%@", base);
        StorageSubclass *storage = (id)base;
        storage->c = 0xDEADBEEF;
        NSLog(@"%X == %X", storage->c, *random);
    }
    

    and the output

    2011-12-14 16:52:54.886 Test[55081:707] <BaseClass: 0x100114140>
    2011-12-14 16:52:54.889 Test[55081:707] <PlainSubclass: 0x100114140>
    2011-12-14 16:52:54.890 Test[55081:707] <StorageSubclass: 0x100114140>
    2011-12-14 16:52:54.890 Test[55081:707] DEADBEEF == DEADBEEF
    

    As you can see the write to storage->c wrote outside the memory allocated for the instance, and into the block I allocated for random. If that was another object, you just destroyed its isa pointer.

    0 讨论(0)
提交回复
热议问题