在 iOS 11 中,Apple 通過NSItemProvider該類向作業系統引入了拖放 API(主要是為了支持 iPadOS 上的應用程式之間的拖動),并為 UITableView 提供了自定義實作UITableViewDragDelegate和UITableViewDropDelegate.
除非我在使用 tableViews 的 diffable 資料源時遺漏了一些東西(總是可能的!),否則使用這些 API 的最佳方法是將底層包裝item在從當前快照獲得的資料源中,NSItemProvider然后將其嵌入到 a 中UIDragItem以方便通過委托方法拖放。特別是在拖動委托中,例如:
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 值型別也必須橋接到它們的舊等效項(例如Stringto NSString、Datato NSData)才能與這些 API 一起使用。
這讓我想到了問題的關鍵:我希望將這些拖放 API 引入已建立的代碼庫,其中底層資料物件出于充分的理由都是值型別。出于多種原因,我不愿意將這些結構更改為類,包括引入新的錯誤和回歸。
我已經考慮(但尚未測驗)只是將這些資料物件包裝在 tableView 的視圖模型中的類物件中。讓包裝類初始化器采用原始結構并將其添加到類中的屬性中。然后使這個包裝類符合必要的協議。盡管這是一種開銷,如果可能的話,我寧愿避免,因為這意味著更改 tableView 方法并實作一種方法來寫回對更廣泛資料模型中底層結構的任何更改。另外,我還不知道NSItemProvider在自定義類中需要支持的 if 協議是否從值型別屬性可能有問題的任何其他協議繼承。
如果有人對如何最好地解決這個問題有任何建議,將不勝感激(請不要建議第三方庫,因為這不是我想要的路線)。
uj5u.com熱心網友回復:
在引入 diffable 資料源 API 之前,我在 Mac 端 (NSTableView) 上遇到過這個問題。
你不會喜歡聽這個,但我完全建議你去上課,100%。
正如您所注意到的,AppKit/UIKit 非常依賴于 Objective C 所圍繞的“物件是具有標識的參考”概念。這些 API 早于該Identifiable協議,盡管該協議幾乎是隱式存在的。每個都NSObject符合它,它的識別符號總是它的物件地址(物件標識)。
您可能有一些作為結構體有意義的結構體(因為它們是具有價值平等且沒有身份的簡單值),但我認為一旦您將它們放入表格中,事情就會發生變化。當您這樣做時,盡管值相等,但Bob Smith第 4Bob Smith行與第 7行變得不相同。它們在視圖中的位置為它們提供了一個新的身份維度,結構無法按原樣處理。
更糟糕的是,許多這些依賴于身份的 API 使用Any, 而不是AnyObject. 如果您匯入了 Foundation,嘗試將值型別傳遞給 Objective C API 會使 Swift 隱式地??將它們裝箱到_SwiftValue物件中。
這些物件遠離您,并在幕后創建/銷毀。與任何其他物件一樣,它們具有基于其地址的已定義身份,但這不是您可以輕松訪問的,當然也不是您可以依賴的。(例如,如果您兩次回傳相同的 struct 值,您將獲得兩個副本,每個副本都包裹在一個不同的 中_SwiftValue。這兩個將是不同的)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/363808.html
