NSView子类如何与控制器通信?

时间:2011-07-31 17:26:59

标签: cocoa macos nsview

我是Cocoa编程的新品牌,我仍然对事物如何连接感到困惑。

我需要一个非常简单的应用程序,只要点击窗口上的任何一点,它就会触发一个命令(让我们称之为DoStuff)。经过一些研究后,看起来子类NSView是正确的方法。我的ClickerView.m文件包含:

- (void)mouseDown:(NSEvent *)theEvent {
    NSLog(@"mouse down");
}

我已经将视图添加到窗口并使其在整个事物中延伸,并且每次单击窗口时都正确地写入日志。

我的控制器上也有doStuff方法(这可以重构为我自己的类,但是现在它可以工作):

- (IBAction)doStuff:(id)sender {
    // do stuff here
}

那么,如何让mouseDown中的ClickerView能够在控制器中调用DoStuff?我有一个强大的.NET背景,有了这个,我只在ClickerView中有一个自定义事件,Controller会消耗掉;我只是不知道如何在Cocoa中做到这一点。

根据Joshua Nozzi的建议进行编辑

我在我的视图中添加了IBOutlet(并将其更改为子类NSControl):

@interface ClickerView : NSControl {
    IBOutlet BoothController *controller;
}
@end

通过单击并从View上Outlets面板中的controller项目拖动到控制器,我将控制器连接到它。我的mouseDown方法现在看起来像:

- (void)mouseDown:(NSEvent *)theEvent {
    NSLog(@"mouse down");
    [controller start:self];
}

但是控制器没有实例化,调试器将其列为0x0,并且不发送消息。

3 个答案:

答案 0 :(得分:12)

您可以将其添加为像Joshua所说的IBOutlet,或者您可以使用委托模式。

您将创建一个描述委托方法的协议,如

@protocol MyViewDelegate
    - (void)doStuff:(NSEvent *)event;
@end

然后你会让你的视图控制器符合MyViewDelegate协议

@interface MyViewController: NSViewController <MyViewDelegate> {
    // your other ivars etc would go here 
}
@end

然后你需要提供doStuff的实现:在MyViewController的实现中:

- (void)doStuff:(NSEvent *)event
{
    NSLog(@"Do stuff delegate was called");
}

然后在您的视图中,您将为委托添加弱属性。委托应该是弱的,这样就不会形成保留循环。

@interface MyView: NSView

@property (readwrite, weak) id<MyViewDelegate> delegate;

@end

然后在你看来你会有类似的东西

- (void)mouseDown:(NSEvent *)event
{
    // Do whatever you need to do

    // Check that the delegate has been set, and this it implements the doStuff: message
    if (delegate && [delegate respondsToSelector:@selector(doStuff:)]) {
        [delegate doStuff:event];
    }
 }

最后:)每当视图控制器创建视图时,您需要设置委托

 ...
 MyView *view = [viewController view];
 [view setDelegate:viewController];
 ...

现在,无论何时单击视图,都应调用视图控制器中的委托。

答案 1 :(得分:2)

首先,您的视图需要对控制器的引用。这可以是在运行时设置的简单iVar或在设计时连接的插座(由IBOutlet指定)。

其次,NSControl是NSView的子类,它免费提供target/action机制机制。用于目标/动作样式控件。这提供了一种设置对控制器(目标)的引用和触发时调用的方法(操作)的简单方法。即使你不使用单元格,你仍然可以轻松地使用目标/动作(NSControl通常只是将这些东西转发到它的NSCell子类的实例,但不必)。

答案 2 :(得分:0)

您还可以使用选择器调用方法, 在自定义类中定义两个属性:

@property id parent;
@property SEL selector;

在视图控制器中设置它们:

graph.selector=@selector(onCalcRate:);
graph.parent=self;

并致电为:

-(void)mouseDown:(NSEvent *)theEvent {
    [super mouseDown:theEvent];
    [_parent performSelector:_selector withObject:self];
}