【问题标题】:Cocoa Subclassing weirdnessCocoa 子类化怪异
【发布时间】:2014-04-07 08:46:15
【问题描述】:

我试图了解子类化在 Cocoa 中的工作原理。

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

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

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

自定义视图类.h
#import <Cocoa/Cocoa.h>

@interface CustomViewClass : NSView

@end
自定义视图类.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"); 行,以便我可以跟踪正在发生的事情。

在界面生成器中,我选择了自定义视图,并在身份检查器中将其自定义类设置为自定义视图。然后我运行应用程序。

正如预期的那样,我在控制台中收到了Custom View initialised 消息。

我将 NSTextField 添加到窗口中,创建一个新类 TextFieldClass 并且 NSTextField 自定义类与 TextFieldClass 完全相同。我还在与上面相同的位置添加了NSLog(@"Text Field initialised"); 来跟踪事物。

但是,当我运行应用程序时,我只在控制台中收到 Custom View initialised 消息,而不是 NSLog(@"Text Field initialised");message。

所以最初我认为 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");
}

运行应用程序,你瞧,每次我在文本字段中输入时,我都会在控制台中收到 My text changed 消息。

所以我的问题是,这里发生了什么? NSTextField 是如何被初始化的,你如何覆盖它的初始化器?

为什么自定义视图的行为似乎与 NSTextField 不同?

源码here

【问题讨论】:

    标签: objective-c cocoa


    【解决方案1】:

    对于您的第一个问题,NSTextFiled 通过

    初始化
    - (id)initWithCoder:(NSCoder *)aDecoder
    

    在这种情况下,您已经从调色板中拖动了NSTextField,然后在身份检查器中将类更改为您的自定义文本字段类。因此initWithCoder: 将被调用而不是initWithFrame:。从调色板拖动的任何对象(自定义视图除外)也是如此

    相反,如果您从调色板中拖动“自定义视图”并将类更改为您的自定义文本字段类,则会调用 initWithFrame:

    您创建的CustomViewClass 是第二种情况,因此会调用initWithFrame:TextFieldClass 是第一种情况,因此会调用 initWithCoder:

    【讨论】:

    • 是的,这行得通。在哪里可以找到控件的初始化程序是什么?我查看了 NSTextField 的 API 参考,但未列出 initWithCoder。
    • 你需要继续继承..并检查超类的文档.. initWithCoder: 在 NSObject 中声明
    【解决方案2】:

    如果你在 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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-02
      • 2013-03-25
      • 2022-01-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多