子类化从nib加载的UIView子类

时间:2013-09-02 01:56:37

标签: ios objective-c

我有一个类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

2 个答案:

答案 0 :(得分:7)

斯威林不是(永远)的答案。

问题在于您的NIB;它被归档,对象[0]是FooView的实例,而不是FooSubclassView。如果要将相同的 NIB与不同的视图子类作为对象[0]加载,则需要将实例移出NIB的存档。

可能最容易做的事情是,因为您的类已经加载了NIB,所以要创建FooViewFooSubclassView 文件所有者的实例。

这个问题对文件的所有者模式有一个很好的解释。请注意,您已经在那里,因为您的类无论如何都在加载XIB / NIB。

以下是官方docs on File's Owner

答案 1 :(得分:1)

我不确定你是不是最好的解决方案,但我认为这正是你要找的。

+ (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];
}