Objective-C:如何在运行时更改对象的类?

ma1*_*w28 9 runtime protected objective-c uitableview

我尝试回答使用带有ISA切换的UITableViewController的UITableView子类,如下所示:

self.tableView->isa = [MyTableView class];
Run Code Online (Sandbox Code Playgroud)

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

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

我问,因为@AmberStar对这个问题的回答似乎有些缺陷.(见我的评论.)

Jos*_*erg 24

如果你的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);
}
Run Code Online (Sandbox Code Playgroud)

和输出

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

正如你所看到的那样,写入在storage->c为实例分配的内存之外写入,并进入我为随机分配的块.如果那是另一个对象,你只需要销毁它的isa指针.

  • 说@JoshuaWeinberg,你知道使用[关联引用](http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html)是否会不好知道与类别一起使用是安全的(我自己使用过几次),但如果子类需要另一个变量,我认为这可以解决问题...... (2认同)

jus*_*tin 5

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

交换isa不安全 - 您不知道类的内存布局是什么或将来会是什么.即使向上移动继承图也是不安全的,因为对象的初始化和破坏将无法正确执行 - 使对象处于可能无效的状态(这可能会导致整个程序失效).

  • @Matt是的,您可以继承`UITableView`,但是您必须在更改表类型的过程中销毁重建表.在更复杂的场景中,您可能更喜欢可以更容易地换出的对象(例如,对外观进行样式化或以不同方式呈现数据的对象). (2认同)