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

问题描述 投票:9回答:3

我是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的建议编辑

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

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

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

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

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

cocoa macos nsview
3个回答
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];
 ...

现在,只要单击视图,就应该调用视图控制器中的委托。


2
投票

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

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


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];
}
© www.soinside.com 2019 - 2024. All rights reserved.