0

在 iOS 11 中,Apple 通过该类向操作系统引入了拖放 API(主要是支持在 iPadOS 上的应用程序之间进行拖动),NSItemProvider并为 UITableView 提供了自定义实现,其中包含UITableViewDragDelegateUITableViewDropDelegate.

除非我在处理 tableViews 的 diffable 数据源时遗漏了某些东西(总是可能的!),否则使用这些 API 的最佳方法是将底层封装item在从当前快照获得的数据源中,NSItemProvider然后将其嵌入到 aUIDragItem中以方便通过委托方法拖放。特别是在拖动委托中,例如:

extension DeliveryViewController :  UITableViewDragDelegate  {
   func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
      let itemType = UTType(exportedAs: "MyDataObject", conformingTo: .item).identifier
      let item = dataSource.itemIdentifier(for: indexPath)!
      let itemProvider = NSItemProvider(item: item, typeIdentifier: itemType)
      return [UIDragItem(itemProvider: itemProvider)]
   }
}

但是,要使用 NSItemProvider,底层数据对象需要符合NSObjectNSItemProviderReadingNSItemProviderWriting。这是为常见NSxxx数据类型提供的,但任何自定义数据对象都需要采用这些。如果您的数据对象是一个类,那么遵守这些协议相对简单,但如果它是一个值类型,则不是因为这些是类协议。甚至原生 Swift 值类型也必须桥接到它们的旧版等价物(例如Stringto NSStringDatato NSData)才能与这些 API 一起使用。

这让我想到了问题的症结所在:我希望将这些拖放 API 引入到已建立的代码库中,其中底层数据对象出于充分的理由都是值类型。出于多种原因,我不愿意将这些结构更改为类,包括引入新的错误和回归。

我已经考虑(但尚未测试)只是将这些数据对象包装在 tableView 的视图模型中的类对象中。让包装类初始化程序获取原始结构并将其添加到类中的属性中。然后使这个包装类符合必要的协议。不过,如果可能的话,这是我宁愿避免的开销,因为这意味着更改 tableView 方法并实现一种方法来将任何更改写回更广泛的数据模型中的底层结构。另外,我还不知道NSItemProvider自定义类中需要支持的 if 协议是否继承自值类型属性可能有问题的任何其他协议。

如果有人对如何最好地解决这个问题有任何建议,将不胜感激(请不要建议第三方库,因为这不是我想要追求的路线)。

4

1 回答 1

1

在引入 diffable 数据源 API 之前,我在 Mac 端(NSTableView)遇到了这个问题。

你不会喜欢听这个,但我完全建议你去上课,100%。

正如您所注意到的,AppKit/UIKit 非常依赖于 Objective C 所围绕的“对象是具有标识的引用”概念。这些 API 早于Identifiable协议,尽管它几乎就像该协议隐式存在。EveryNSObject符合它,它的标识符始终是它的对象地址(对象标识)。

您可能有一些结构有意义的结构(因为它们是具有值相等且没有身份的简单值),但我认为一旦您将它们扔到表中,情况就会改变。这样做的那一刻,Bob Smith第 4Bob Smith行与第 7 行不同,尽管值相等。它们在视图中的位置为它们提供了一个新的身份维度,结构无法按原样处理。

更糟糕的是,很多这些与身份相关的 API 使用Any. 而不是AnyObject. 如果你已经导入了 Foundation,尝试将值类型传递给 Objective C API 将使 Swift 隐式地​​将它们装箱到_SwiftValue对象中。

这些对象隐藏在远离您的地方,并在幕后创建/销毁。与任何其他对象一样,它们具有基于其地址的已定义身份,但这不是您可以轻松访问的东西,当然也不是您可以依赖的东西。(例如,如果您两次返回相同的结构值,您将获得两个副本,每个副本都包装在不同的_SwiftValue. 两个将不相同)

于 2021-11-09T13:41:48.937 回答