NSPasteboard 和简单的自定义数据
我在尝试让 NSPasteboard 工作时遇到了很大的困难,所以请原谅我的缺乏理解。
我想要的只是一种简单的方法来从粘贴板写入和检索仅适用于我的应用程序的 NSUInteger 值。我所做的只是在应用程序中拖放一个项目,因此粘贴板中我需要的只是该项目的 ID。
我尝试过研究 NSPasteboardItemDataProvider 和 NSPasteboardItem 以及 NSData,但它们都有复杂的方法来做如此简单的事情。事实上,我不知道做如此简单的事情的正确方法是什么 - 每个示例似乎都处理字符串类型,或者更复杂的东西。尽管代码中没有警告,[NSMutable SetData] 选择器似乎也不存在。
如果有人能指出我正确的方向,我将非常感激。 :)
编辑:我正在使用 [dragImage ...] 来帮助我进行拖动操作。
I'm having a really difficult time trying to get NSPasteboard to work, so forgive me for my lack of understanding.
All I want is a simple way to write and retrieve from the pasteboard a NSUInteger value that is only for my application. All I am doing is drag dropping an item within my application, so all I need in the pasteboard is the item's id.
I have tried looking into NSPasteboardItemDataProvider and NSPasteboardItem, and NSData, but they all have convoluted way of doing something so simple. Infact, I have no idea what is the correct way of doing something so simple - every sample around seems to deal with the string type, or something much more complicated. [NSMutable SetData] selector doesn't seem to exist either even though there are no warnings in the code.
If someone can point me in the right direction, I would be very grateful. :)
Edit: I am using [dragImage ...] to help me with my dragging operations.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
有两种使用 NSPasteboard 的方法。
旧方法:自己将数据固定到开发板上
首先,您必须 声明您将放置在粘贴板。您还指定一个将“拥有”粘贴板的对象,这意味着这是将内容放在粘贴板上的对象。
下一步是将数据放在粘贴板上。此步骤是可选的。
“可选?!”,你问。是:如果您没有将已声明的任何类型的数据放在粘贴板上,并且粘贴板随后需要该数据(粘贴/删除),则 粘贴板会向您(所有者)询问。这称为承诺数据,当复制(大量)或生成该数据的成本很高时,这是很好的选择。
有五种方法可以将内容放在粘贴板上(除了被要求提供之外):
较新的方法:将对象固定到板上并让它们将自己转换为数据
Snow Leopard 中引入的新功能是让对象本身能够将自己写入粘贴板。这确实要求他们了解您希望在粘贴板上显示的关于他们自己的一切,包括标识符。
您需要使您的对象符合 NSPasteboardWriting 和 NSPasteboardReading。
既然您知道了旧的方法,那么编写协议看起来就会非常熟悉。粘贴板询问您的对象它将自己表示为什么类型,然后要求它提供每种类型的属性列表对象。 (该协议还提供了一种承诺类型的方法,而不是立即请求它们的数据。)
要将符合 NSPasteboardWriting 的对象复制到粘贴板,请向粘贴板发送
clearContents
消息(新版本中需要)方式,旧方式可选),然后writeObjects:
传递要复制的对象的数组。正如您所期望的,阅读协议是相反的。要粘贴,请发送粘贴板 a
readObjectsForClasses:options:
消息。粘贴板询问每个类 它将识别什么类型,然后(可选)尝试从粘贴板上的内容实例化其中一个或多个。这样做的缺点,特别是在涉及重用标识符的情况下,它最终可能会破坏模型层与控制器层的分离。 如果您希望读取初始化程序返回具有该标识符的现有对象。这意味着它需要与控制器对话(不好)或复制控制器的查找代码(更糟糕)。
我不知道有什么好方法可以使用新协议实现移动拖放(包括但不限于重新排序)而不会遇到此问题。对于复制拖放(包括但不限于跨进程),这很好,因为您不需要为此使用标识符 - 只需在一端生成数据并在另一端从中创建新副本。
新方法的优点是处理多个项目更加理智。在旧的方式中,只有一个“项目”——实际上,根本没有任何项目的概念——有多种类型。如果您想复制或拖动多个内容,您可以创建一个数组并将其复制为某种类型的单个属性列表,然后从另一端的单个属性列表中重新创建/检索多个内容。较新的方式明确支持一项或多项;复制多个内容时,只需将它们全部传递给
writeObjects:
即可。您的情况:单个 NSUInteger 标识符
将其放入 NSNumber (这是一个属性列表)中并以旧的方式使用它。
There are two ways to use NSPasteboard.
The older way: Pin data to the board yourself
First, you must declare the types that you will put on the pasteboard. You also appoint an object that will “own” the pasteboard, meaning that this is the object putting stuff on the pasteboard.
The next step is to put data on the pasteboard. This step is optional.
“Optional?!”, you ask. Yes: If you don't put data on the pasteboard for any type you have declared, and the pasteboard subsequently needs that data (to paste/drop), then the pasteboard will ask you (the owner) for it. This is called promising that data, and it's good when that data is expensive to copy (large) or generate.
There are five ways to put things on the pasteboard (besides getting asked for them):
The newer way: Pin objects to the board and let them turn themselves into data
The new hotness, introduced in Snow Leopard, is to make your objects themselves able to write themselves to a pasteboard. This does require that they know everything about themselves that you will want on the pasteboard, including identifiers.
You need to make your objects conform to both NSPasteboardWriting and NSPasteboardReading.
The writing protocol will look really familiar now that you know the older way. The pasteboard asks your object what types it would represent itself as, then asks it for a property-list object for each type. (The protocol also provides a way to promise types instead of having the data for them requested immediately.)
To copy objects that conform to NSPasteboardWriting to the pasteboard, send the pasteboard a
clearContents
message (required in the new way, optional in the old way), thenwriteObjects:
passing an array of the objects you want to copy.The reading protocol is, as you'd expect, the inverse. To paste, you send the pasteboard a
readObjectsForClasses:options:
message. The pasteboard asks each of those classes what types it would recognize, then (optionally) tries to instantiate one or more of them from what's on the pasteboard.The downside of this, particularly where reuse identifiers are concerned, is that it can end up breaking the separation of your model layer from your controller layer. Your reading initializer will need to know what to do with an identifier if you want it to return the existing object that has that identifier. That means it needs to either talk to the controller (bad) or duplicate the controller's lookup code (worse).
I don't know of a good way to implement move drag-and-drop (including, but not limited to, reordering) with the new protocols without running into this problem. For copy drag-and-drop (including, but not limited to, cross-process), it's fine, since you don't need identifiers for that—just generate the data on one end and create the new copy from it on the other.
The upside of the newer way is that handling of multiple items is much more sane. In the older way, there's only one “item”—indeed, not really any concept of items at all—in multiple types. If you wanted to copy or drag multiple things, you made an array and copied that as a single property list for some type, then re-created/retrieved the multiple things from that single property list on the other end. The newer way explicitly supports one or more items; when copying multiple things, you simply pass them all to
writeObjects:
.Your case: A single NSUInteger identifier
Box it in an NSNumber (which is a property list) and use it in the older way.
要跟进 Peter Hosey 的回答,请查看 PlaylistViewController.swift href="https://github.com/slashlos/Helium" rel="nofollow noreferrer">Helium 端口。该模块处理自定义对象的拖放以及与 WKWebView 的交互。
这是一项正在进行中的工作,采用了新的闪亮纸板。
To follow up on Peter Hosey's, answer, take a look at PlaylistViewController.swift of my GitHub Helium port. This module handles the drag-n-drop for custom objects and interactions with a WKWebView.
It's a working, work in progress featuring the new shiny pasteboard adoption.