【问题标题】:Objective-C: How to change the class of an object at runtime?Objective-C:如何在运行时更改对象的类?
【发布时间】:2012-01-20 17:14:12
【问题描述】:

我尝试用ISA Switching 回答Using a UITableView subclass with a UITableViewController,如下所示:

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

但是,我得到了编译错误:Instance variable 'isa' is protected.

有没有办法解决这个问题?如果是这样,这样做是否安全?

我问是因为@AmberStar's answer to that question 似乎有点缺陷。 (见我的评论。)

【问题讨论】:

    标签: objective-c runtime uitableview protected


    【解决方案1】:

    如果您的 tableview 类提供任何存储,这将中断。我不会推荐你走的路。但正确的方法是使用object_setClass(tableView, [MyTableView class])

    请确保这确实是您想要的。

    这是一个小代码示例,展示了这是一个多么可怕的想法。

    #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);
    }
    

    和输出

    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
    

    如您所见,对storage-&gt;c 的写入写入了为实例分配的内存之外,并写入了我为随机分配的块中。如果那是另一个对象,您只需销毁它的 isa 指针。

    【讨论】:

    • 非常感谢。但是,将UITableViewController 中的self.tableView 设置为UITableView 的自定义子类的新实例是否安全?
    • say @JoshuaWeinberg,你知道使用Associative References 会不会不好我知道与类别一起使用是安全的(我自己用过几次)但是如果子类需要另一个变量,我认为这会成功......
    • 我一直都在用,很方便。
    • 哇!那是一个快速的答复!你会因此得到一分! :) - 现在我明白你是如何得到你的 Fanatic badge... :)
    【解决方案2】:

    安全的方法是创建一个新实例。

    交换isa 是不安全的——你不知道一个类的内存布局是什么,也不知道它将来会是什么。即使向上移动继承图也确实不安全,因为对象的初始化和销毁​​不会正确执行 - 使您的对象处于潜在的无效状态(这可能会导致整个程序停止运行)。

    【讨论】:

    • 酷,谢谢。但是,将UITableViewController 中的self.tableView 设置为UITableView 的自定义子类的新实例是否安全?
    • @Matt 是的,你可以继承UITableView,但是你必须在改变表类型的过程中破坏重建表。在更复杂的场景中,您可能更喜欢可以更轻松地换出的对象(例如,对外观进行样式设置或以不同方式呈现数据的对象)。
    猜你喜欢
    • 1970-01-01
    • 2013-07-09
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    相关资源
    最近更新 更多