我尝试用Using a UITableView subclass with a UITableViewController回答ISA Switching,如下所示:
self.tableView->isa = [MyTableView class];
但是,我收到编译错误:Instance variable 'isa' is protected.
有没有办法解决这个问题?如果是这样,这样做是否安全?
我问,因为@AmberStar's answer to that question似乎有点瑕疵。 (见我的评论。)
答案 0 :(得分: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);
}
和输出
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->c
的写入在为实例分配的内存之外写入,并且写入我为随机分配的块中。如果那是另一个对象,你只需要销毁它的isa
指针。
答案 1 :(得分:5)
安全的方法是创建一个新实例。
交换isa
并不安全 - 您不知道类的内存布局是什么或将来会是什么。即使向上移动继承图也是不安全的,因为对象的初始化和破坏将无法正确执行 - 使对象处于可能无效的状态(这可能会导致整个程序崩溃)。