子类化和覆盖使用 nib 文件创建的 UIView
Posted
技术标签:
【中文标题】子类化和覆盖使用 nib 文件创建的 UIView【英文标题】:Subclassing and overriding a UIView created with a nib file 【发布时间】:2012-03-07 23:43:25 【问题描述】:假设我创建了一个 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
方法,结果是控制台中的Fired MySubView
。
我该如何解决这个问题?
我想保留笔尖布局,但给它一个新的类。
【问题讨论】:
检查这个***.com/questions/1923720/…> 【参考方案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 初始化程序的抽象类(存根),而您要创建的 UIView 是它的子类:
MyAbstractNibUIView initWithNibFile:withFrame:
MyRedSubview : MyAbstractNibUIView red.xib
MyGreenSubview :MyAbstractNibUIView green.xib
MyBlueSubview : MyAbstractNibUIView blue.xib
【讨论】:
【参考方案2】:当您调用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 中都调用它。
【讨论】:
以上是关于子类化和覆盖使用 nib 文件创建的 UIView的主要内容,如果未能解决你的问题,请参考以下文章
Swift 中的 NSWindowController。使用 Nib 进行子类化和初始化
如何在 UIView 的子类中同时覆盖 initWithFrame: 和 initWithCoder:?