首页 文章

子类化从nib加载的UIView子类

提问于
浏览
11

我有一个类 FooView ,它是 UIView 的子类,其视图是从一个nib加载的,类似于:

+ (instancetype)viewFromNib
{
    NSArray *xib = [[NSBundle mainBundle] loadNibNamed:@"FooView" owner:self options:nil];
    return [xib objectAtIndex:0];
}

nib本身在Identity Inspector中将其Custom Class设置为 FooView .

这被实例化为:

FooView *view = [FooView viewFromNib];

这表现得像你期望的那样 . 但是,当FooView本身被子类化为FooSubclassView,并实例化为:

FooSubclassView *view = [FooSubclassView viewFromNib];

view 仍然是 FooView 类型,而不是 FooSubclassView .

使用 object_setClass 对类进行调配并不能解决基础对象是 FooView 的实例的问题,因此在子类实例上调用的方法将是超类( FooView )的方法,而不是 FooSubclassView .

我如何纠正这一点,以便子类具有正确的类型,而不必为每个子类创建一个新的nib,或者必须在每个子类中重新实现 viewFromNib

2 回答

  • 1

    调酒不是(永远)的答案 .

    问题出在你的NIB上;它被归档,对象[0]是 FooView 的一个实例,而不是 FooSubclassView . 如果要将具有不同视图子类的相同NIB作为对象[0]加载,则需要将实例移出NIB的存档 .

    可能是最简单的事情,因为你的类已经加载了NIB,所以要创建 FooViewFooSubclassView 文件所有者的实例 .

    这个问题对File的Owner模式有一个很好的解释 . 请注意,您几乎已经在那里,因为您的类无论如何都在加载XIB / NIB .

    这是官方的docs on File's Owner .

  • 7

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

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

相关问题