子类化和覆盖使用nib文件创建的UIView

时间:2012-03-07 23:43:25

标签: uiview initialization override subclass nib

假设我已经创建了UIView的子类,并且我用nib文件加载它。
我这样做:

MySubView.m  

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MySubView" owner:self options:nil];

        [self release];
        self = [[nib objectAtIndex:0] retain];
        self.tag = 1;
        [self fire];
    }
    return self;
}

- (void)fire {
   NSLog(@"Fired MySubView");
}

现在我想创建一些变体,但我不想复制nib文件,所以我尝试像这样子类化MySubView,改变背景颜色:

RedMySubView.m  


- (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
    if (self) {
       self.backgroundColor = [UIColor redColor];
       [self fire];
    }
    return self;
}

- (void)fire {
   NSLog(@"Fired RedMySubView");
}

创建视图,更改背景颜色,但子类不会覆盖fire操作。如果我调用fire方法,则控制台中的结果为Fired MySubView 我该如何解决这个问题? 我想保留笔尖布局,但是给它一个新的类。

2 个答案:

答案 0 :(得分:1)

我会说,在MySubview初始化程序initWithFrame中使用[self release],您将丢弃要使用初始化程序创建的类。该类由loadNibName方法加载,因此具有与nib中定义的相同的类。 因此,在子类中调用初始化程序是没用的。

尝试在MySubview中实现自己的nib构造函数(例如initWithNibFile):

- (id) initWithNibFile:(NSString *) nibName withFrame:(CGRect) frame

等。并在RedMySubview中调用此构造函数

- (id) initWithNibFile:(NSString *) nibName withFrame:(CGRect) frame {
self = [super initWithNibFile:mynib withFrame:MyCGRect];
if (self)
....

如果您现在查找您的nib文件确实将RedMySubview作为类,那应该是fire 重写。如果您使用两者 MySubview和RedMySubview,则必须复制xib。 或者您创建一个抽象类(存根),它只实现initWithNibFile初始化程序,您想要创建的UIViews是它的子类:

MyAbstractNibUIView initWithNibFile:withFrame:
MyRedSubview : MyAbstractNibUIView        red.xib
MyGreenSubview :MyAbstractNibUIView       green.xib 
MyBlueSubview : MyAbstractNibUIView       blue.xib

答案 1 :(得分:1)

当你调用self = [[nib objectAtIndex:0] retain]时,你基本上覆盖你的“self”对象成为MySubView,因为MySubView是nib文件中的基础对象。这是不受欢迎的,因为如果调用类是RedMySubView,那么它将被重写为MySubView。

相反,您希望将MySubView中的- (id)initWithFrame:(CGRect)frame更改为:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MySubview" owner:self options:nil];

        // The base of the nib file. Don't set self to this, instead copy all of its
        // subviews, and "self" will always be the class you intend it to be.
        UIView *baseView = [nib objectAtIndex:0];

        // Add all the subviews of the base file to your "MySubview". This
        // will make it so that any subclass of MySubview will keep its properties.
        for (UIView *v in [baseView subviews])
            [self addSubview:v];

        self.tag = 1;
        [self fire];
    }
    return self;
}

现在,一切都应该在“MyRedSubView”的初始化程序中起作用,除了fire会激发两次,因为你在MySubView和RedMySubView中都调用它。

相关问题