我尝试回答如何在UITableViewController中使用UITableView子类,并使用ISA切换来实现:
self.tableView->isa = [MyTableView class];
但是,我遇到了编译错误:实例变量 'isa' 是受保护的。
有没有办法规避这种情况?如果有,是否安全呢?
我问这个问题是因为@AmberStar对那个问题的回答似乎有点瑕疵(见我的评论)。
我尝试回答如何在UITableViewController中使用UITableView子类,并使用ISA切换来实现:
self.tableView->isa = [MyTableView class];
但是,我遇到了编译错误:实例变量 'isa' 是受保护的。
有没有办法规避这种情况?如果有,是否安全呢?
我问这个问题是因为@AmberStar对那个问题的回答似乎有点瑕疵(见我的评论)。
如果你的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
指针。
安全的方法是创建一个新实例。
交换 isa
不安全 - 你不知道类的内存布局或将来会是什么样子。即使向上移动继承图也不安全,因为对象的初始化和销毁不会正确执行 - 可能会使对象处于无效状态(可能导致整个程序崩溃)。
UITableViewController
中将self.tableView
设置为自定义的UITableView
子类的新实例是安全的吗? - ma11hew28UITableView
,但在更改表格类型的过程中,你必须销毁并重建表格。在更复杂的情况下,你可能更喜欢一个可以更轻松地替换的对象(例如,一个可以不同地呈现数据或样式的对象)。 - justin
UITableViewController
中将self.tableView
设置为自定义的UITableView
子类的新实例是否安全? - ma11hew28