NIB文件中的子类UIView未输入子类

我有一个NIB文件,其中一些类(SomeClassView:UIView)被设置为NIB顶级视图的自定义类。 SomeClass有IBOutlets,用于连接我在Interface Builder中布局的SomeClass的子视图。

我像这样实例化SomeClass:

- (id)initWithFrame:(CGRect)frame {
    self = [[[[NSBundle mainBundle] loadNibNamed:@"SomeClassView" owner:nil options:nil] objectAtIndex:0] retain]; 
    // "SomeClassView" is also the name of the nib
    if (self != nil) {
        self.frame = frame;
    }
    return self;
}

现在说我用SubClassView子类SomeClass。 我向SubClassView中添加一个名为 - (void)foo的方法:

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self != nil) {
        [self foo];
    }
    return self;
}

在这一点上,我得到一个运行时错误:*由于未捕获异常'NSInvalidArgumentException'终止应用程序,原因:' - [SomeClassView foo:]:无法识别的选择器发送到实例0xAAAAAA'

似乎在SubClassView的initWithFrame中的“self”仍然被设置为超级SomeClassView。 解决此问题的快速修复方法是更改​​SubClassView initWithFrame中的isa指针:

- (id)initWithFrame:(CGRect)frame {
    Class prevClass = [self class];
    self = [super initWithFrame:frame];
    if (self != nil) {
        isa = prevClass;
        [self foo]; // works now
    }
 }

这不是一个理想的解决方法,因为每次我子类化时都必须更新isa,或者甚至可能有不同的init方法,我还必须更新它们。

1)理想情况下,是否有简单的方法来解决这个问题,纯粹由代码? 也许用我设置self =装载的笔尖的方式?

2)是否有另一种架构更适合我想要做的事情? 一个例子是将所有者设置为self,但是您必须手动设置所有的property / outlet映射。


如果您的子类具有非在SomeClassView声明的实例变量,则交换isa指针是个问题。 请注意,您的nib文件具有SomeClassView类型的对象,这意味着,在加载nib文件时,nib加载器将分配该类型的对象并从nib文件解开它。 暂时将isa指针更改为[SubViewClass class]不会使其成为SubViewClass类型的对象,因为nib加载器分配的是SomeClassView对象。

也就是说,我不认为有一种可靠和自动的方式来使用包含对象的nib文件,这些对象的类型需要在加载nib时进行更改。

你可以做的是让你的SomeClassView对象声明一个符合某种协议的委托。 该协议将定义可能被扩展的SomeClassView中的行为方法。 例如,

@protocol SomeClassViewDelegate
@optional
- (void)someClassViewDidAwakeFromNib:(SomeClassView *)someClassView;
@end

而不是子类化SomeClassView ,你会有任意的对象执行您目前在SubClassView任何自定义行为。 例如,

@interface SubClassViewBehaviour : NSObject <SomeClassViewDelegate>
…
@end

@implementation SubClassViewBehaviour
- (void)someClassViewDidAwakeFromNib:(SomeClassView *)someClassView {
    // whatever behaviour is currently in -[SubClassView foo]
}
@end

SubClassViewBehaviour对象将在代码中创建,并在加载nib文件或任何其他IB代理对象时作为nib文件的所有者。 SomeClassView将有一个委托出口连接到文件的所有者/代理对象,它会在适当的位置调用委托方法。 例如,

@implementation SomeClassView
- (void)awakeFromNib {
    SEL didAwakeFromNib = @selector(someClassViewDidAwakeFromNib:);
    if ([[self delegate] respondsToSelector:didAwakeFromNib]) {
        [[self delegate] performSelector:didAwakeFromNib withObject:self];
    }
}
@end

还有一点评论:你的代码当前泄漏了一个视图对象,因为两个对象正在被实例化:一个通过代码中的+alloc和另一个通过nib加载。 你将后者分配给self ,因此通过+alloc创建的那个泄漏。 另外,我相信您在第三个代码段中错过了对super的调用。


而不是在子类本身内部做到这一点,为什么不从类之外实例化时确保它是正确的类:

SubClass *instance = [[SubClass alloc] initWithNibName:@"SomeClassView" bundle:nil];
链接地址: http://www.djcxy.com/p/87717.html

上一篇: Subclassed UIView from NIB File not typed to subclass

下一篇: Change TabBarItem text in WindowBased app