我试图理解Subclassing在Cocoa中是如何工作的。
我在XCode 5.1中创建了一个新的Cocoa应用程序项目。
我将新的自定义视图拖到主窗口上。
我创建了一个新的Objective-C类CustomViewClass
并将其设置为NSView
的子类。这会产生以下结果:
#import <Cocoa/Cocoa.h>
@interface CustomViewClass : NSView
@end
CustomViewClass.m
#import "CustomViewClass.h"
@implementation CustomViewClass
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
NSLog(@"Custom View initialised");
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
}
@end
请注意,我添加了NSLog(@"Custom View initialised");
行,以便我可以跟踪正在发生的事情。
在界面生成器中,我选择了自定义视图,并在Idenditiy Inspecter中将其自定义类设置为CustomView。然后我运行应用程序。
正如预期的那样,我在控制台中收到了Custom View initialised
消息。
我使用NSTextField将其添加到窗口,创建新类TextFieldClass
并且NSTextField自定义类是TextFieldClass。我还在上面的同一个地方添加NSLog(@"Text Field initialised");
来跟踪事情。
但是,当我运行应用时,我只在控制台中收到Custom View initialised
消息,而不是NSLog(@"Text Field initialised");
消息。
所以最初我认为NSTextField在创建时不会收到initWithFrame
消息。所以我在TextFieldClass中添加了一个初始化器:
- (id)init {
self = [super init];
if (self) {
// Initialization code here.
NSLog(@"Text Field initialised");
}
return self;
}
然而,这仍然没有得到调用。
因此我假设NSTextField没有被子类化。但是,当我将此方法添加到TextFieldClass
:
-(void)textDidChange:(NSNotification *)notification {
NSLog(@"My text changed");
}
运行app并看看,每次我输入文本字段时,我都会在控制台中收到My text changed
消息。
所以我的问题是,这里发生了什么?如何初始化NSTextField以及如何覆盖它的初始化?
为什么自定义视图的行为与NSTextField的行为不同?
源代码here
答案 0 :(得分:2)
对于您的第一个问题,NSTextFiled通过
初始化- (id)initWithCoder:(NSCoder *)aDecoder
在这种情况下,您已从调色板中拖动NSTextField
,然后将类更改为身份检查器中的自定义文本字段类。因此将调用initWithCoder:
而不是initWithFrame:。对于从调色板拖动的任何对象(自定义视图除外)也是如此
相反,如果你拖动&#34;自定义视图&#34;从调色板中将类更改为自定义文本字段类,将调用initWithFrame:
。
您创建的CustomViewClass
是第二种情况,因此调用initWithFrame:
。 TextFieldClass
是第一种情况,因此调用了initWithCoder:
。
答案 1 :(得分:1)
如果您在XCode中使用 Interface Builder ,则应使用awakeFromNib
初始化您的子类。
- (void)awakeFromNib
{
// Your init code here.
}
如果要使用接口构建器以编程方式和使用子类,请使用以下代码:
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initView];
}
return self;
}
- (void)awakeFromNib
{
[self initView];
}
- (void)initView
{
// Your init code here
}