Cocoa Subclassing怪异

时间:2014-04-07 08:46:16

标签: objective-c cocoa

我试图理解Subclassing在Cocoa中是如何工作的。

我在XCode 5.1中创建了一个新的Cocoa应用程序项目。

我将新的自定义视图拖到主窗口上。

我创建了一个新的Objective-C类CustomViewClass并将其设置为NSView的子类。这会产生以下结果:

CustomViewClass.h
#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

2 个答案:

答案 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
}