我有一个类FooView
,它是UIView
的子类,其视图是从一个nib加载的,类似于:
+ (instancetype)viewFromNib
{
NSArray *xib = [[NSBundle mainBundle] loadNibNamed:@"FooView" owner:self options:nil];
return [xib objectAtIndex:0];
}
nib本身在Identity Inspector中将自定义类设置为FooView
。
这被实例化为:
FooView *view = [FooView viewFromNib];
这表现得像你期望的那样。但是,当FooView本身被子类化为FooSubclassView,并实例化为:
FooSubclassView *view = [FooSubclassView viewFromNib];
view
仍然是FooView
类型,而不是FooSubclassView
。
使用object_setClass
对类进行调配并不能解决基础对象是FooView
的实例的问题,因此在子类实例上调用的方法将是超类的方法({{1 }}),而不是FooView
。
如何更正这一点,以便子类具有正确的类型,而不必为每个子类创建新的nib,或者必须在每个子类中重新实现FooSubclassView
?
答案 0 :(得分:7)
斯威林不是(永远)的答案。
问题在于您的NIB;它被归档,对象[0]是FooView
的实例,而不是FooSubclassView
。如果要将相同的 NIB与不同的视图子类作为对象[0]加载,则需要将实例移出NIB的存档。
可能最容易做的事情是,因为您的类已经加载了NIB,所以要创建FooView
或FooSubclassView
文件所有者的实例。
这个问题对文件的所有者模式有一个很好的解释。请注意,您已经在那里,因为您的类无论如何都在加载XIB / NIB。
以下是官方docs on File's Owner。
答案 1 :(得分:1)
我不确定你是不是最好的解决方案,但我认为这正是你要找的。 p>
+ (instancetype)viewFromNib
{
NSString *className = NSStringFromClass([self class]);
NSArray *xib = [[NSBundle mainBundle] loadNibNamed:className owner:self options:nil];
return [xib objectAtIndex:0];
}
只要您确定NIB与该类名称相同即可。
在意识到我误认为其中一项要求后,我说我必须同意@bbum。
- (id)init
{
// NOTE: If you don't know the size, you can work this out after you load the nib.
self = [super initWithFrame:GCRectMake(0, 0, 320, 480)];
if (self) {
// Load the nib using the instance as the owner.
[[NSBundle mainBundle] loadNibNamed:@"FooView" owner:self options:nil];
}
return self;
}
+ (instancetype)viewFromNib
{
return [[self alloc] init];
}