在 iOS 11 中,Apple 通过该类向操作系统引入了拖放 API(主要是支持在 iPadOS 上的应用程序之间进行拖动),NSItemProvider
并为 UITableView 提供了自定义实现,其中包含UITableViewDragDelegate
和UITableViewDropDelegate
.
除非我在处理 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,底层数据对象需要符合NSObject
、NSItemProviderReading
和NSItemProviderWriting
。这是为常见NSxxx
数据类型提供的,但任何自定义数据对象都需要采用这些。如果您的数据对象是一个类,那么遵守这些协议相对简单,但如果它是一个值类型,则不是因为这些是类协议。甚至原生 Swift 值类型也必须桥接到它们的旧版等价物(例如String
to NSString
、Data
to NSData
)才能与这些 API 一起使用。
这让我想到了问题的症结所在:我希望将这些拖放 API 引入到已建立的代码库中,其中底层数据对象出于充分的理由都是值类型。出于多种原因,我不愿意将这些结构更改为类,包括引入新的错误和回归。
我已经考虑(但尚未测试)只是将这些数据对象包装在 tableView 的视图模型中的类对象中。让包装类初始化程序获取原始结构并将其添加到类中的属性中。然后使这个包装类符合必要的协议。不过,如果可能的话,这是我宁愿避免的开销,因为这意味着更改 tableView 方法并实现一种方法来将任何更改写回更广泛的数据模型中的底层结构。另外,我还不知道NSItemProvider
自定义类中需要支持的 if 协议是否继承自值类型属性可能有问题的任何其他协议。
如果有人对如何最好地解决这个问题有任何建议,将不胜感激(请不要建议第三方库,因为这不是我想要追求的路线)。