1

我正在非 C 环境中使用 Cocoa 的拖放 API。我将不得不使用 objc/runtime.h 函数,因此我需要了解我必须在哪里注入必要的方法。

现在,SDK 文档说首先在 NSView 或 NSWindow 对象上调用 registerForDraggedTypes。它进一步解释了这两个类都实现了 NSDraggingDestination 协议的存根,然后这些存根方法需要被覆盖(至少 draggingEntered: 和 performDragOperation: 需要;其余的都是可选的)。

到现在为止还挺好。

但是,我发现我也可以在窗口的控制器中实现这些方法,即在一个 NSWindowController 类型的类中。例如,我使用 Apple 的“DemoMonkey”示例执行此操作,其中我在其 DisplayController(它是一个 NSWindowController)中实现了所需的调用,然后在“self.window”上调用了 registerForDraggedTypes。

这怎么行?

我的意思是,在这种情况下,接收到 registerForDraggedTypes 调用的对象与控制器有什么关系,知道它必须向它询问这些拖动回调吗?它在哪里记录了这种方式?

我想知道这是否与 NSWindowController 是 NSResponder 的事实有关。事实上,NSDraggingDestination 调用是否贯穿响应者链?(作为记录:我还尝试创建 NSResponder 的子类,在那里而不是在控制器类中实现回调,创建它的实例并用它调用“self.window makeFirstResponder:”,但这并没有导致在窗口上拖动数据时调用的回调。)

任何人都可以澄清这种行为,并可能解释这个事实记录在哪里(或者这只是未记录的行为,因此不应该依赖?)

4

1 回答 1

1

发生这种情况是因为您发送registerForDraggedTypes:到窗口并且 NSWindowController 是 NSWindow 的委托。

这在“拖放编程主题”中有提到:

尽管 NSDraggingDestination 被声明为一个非正式协议,但您为采用该协议而创建的 NSWindow 和 NSView 子类只需要实现那些相关的方法。(NSWindow 和 NSView 类为所有方法提供私有实现。)窗口对象或其委托都可以实现这些方法;但是,如果两个地方都有实现,则委托的实现优先。

以及 NSWindow 的registerForDraggedTypes:的文档:

为拖动类型注册 NSWindow 对象会自动使其成为拖动会话的候选目标对象。NSWindow 为 NSDraggingDestination 协议中的许多方法提供了默认实现。如果委托响应消息的选择器,则默认实现将每条消息转发给委托。以这种方式转发的消息有draggingEntered:、draggingUpdated:、draggingExited:、prepareForDragOperation:、performDragOperation:、consumerDragOperation:。

如果您想实现“drop view”之类的东西并调用registerForDraggedTypes:NSView,则不会发生这种情况。然后,您需要自己将所有消息转发给控制器。无论哪种情况,我认为控制器无论如何都是更适合拖放处理代码的地方。

于 2013-10-16T09:29:31.320 回答