将 MPMediaItem 包装在结构中时,DiffableDataSource 抛出 "Fatal: supplied identifiers are not unique."
DiffableDataSource throws "Fatal: supplied identifiers are not unique." when wrapping MPMediaItem inside a struct
我使用 UITableviewDiffableDataSource
和 UITableView
来显示音乐库中的歌曲。此代码运行良好:
let tracks: [MPMediaItem] = MPMediaQuery.songs().items ?? []
self.dataSource.apply(section: 0, items: tracks)
但是当我将 MPMediaItem
包装在自定义 Track struct
中时,我得到了这个错误:Fatal: supplied identifiers are not unique.
struct Track: Equatable, Hashable {
let item: MPMediaItem
var title: String? { item.title }
init(item: MPMediaItem) {
self.item = item
}
}
let items = MPMediaQuery.songs().items ?? []
let tracks: [Track] = items.map { Track(item: [=12=]) }
self.dataSource.apply(section: 0, items: tracks)
MPMediaItem
已经符合 Equatable
和 Hashable
所以我认为如果我在另一个也符合 Equatable
和 [=23 的结构中使用它应该没问题=] (Track struct
).
更新 1:apply(section:items:)
是我为了方便添加到 UITableViewDiffableDataSource
的扩展:
extension UITableViewDiffableDataSource {
func apply(section: SectionIdentifierType, items: [ItemIdentifierType], animatingDifferences: Bool = false) {
var snapshot = NSDiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType>()
snapshot.appendSections([section])
snapshot.appendItems(items)
apply(snapshot, animatingDifferences: animatingDifferences)
}
}
更新 2:在我遵守 Track
到 Identifiable
协议后它起作用了:
struct Track: Equatable, Hashable, Identifiable {
let item: MPMediaItem
let id: MPMediaEntityPersistentID
var title: String? { item.title }
init(item: MPMediaItem) {
self.item = item
self.id = item.persistentID
}
}
甚至将 title
更改为存储 属性 也没有任何错误:
struct Track: Equatable, Hashable {
let item: MPMediaItem
let title: String?
init(item: MPMediaItem) {
self.item = item
self.title = item.title
}
}
是什么让这些案例如此不同?为什么在使用 MPMediaItem
作为 Track
结构的唯一存储 属性 时出现错误?提前致谢!
我猜测 MPMediaItem 的可哈希性存在错误。这可能会导致您对所描述的两种情况得到不同的答案。在这个例子中,我会故意制作一个有问题的 NSObject:
class Dog : NSObject {
let name : String?
init(name:String?) {self.name = name}
override func isEqual(_ object: Any?) -> Bool {
if let dog = object as? Dog {
return self.name == dog.name
}
return false
}
}
struct DogHolder : Hashable {
let dog : Dog
var name : String? { dog.name }
}
这是一个测试:
var set = Set<DogHolder>()
let dh1 = DogHolder(dog:Dog(name:"rover"))
let dh2 = DogHolder(dog:Dog(name:"rover"))
set.insert(dh1)
set.insert(dh2)
print(set.count)
do {
var set = Set<Dog>()
let dh1 = Dog(name:"rover")
let dh2 = Dog(name:"rover")
set.insert(dh1)
set.insert(dh2)
print(set.count)
}
运行一遍又一遍的测试。有时我得到 1 和 2。有时我得到 2 和 1。有时我得到 1 和 1。有时我崩溃。
我不知道确切的问题是什么,但显然将 NSObject 可哈希性暴露给 Swift 的可哈希性要求会暴露该错误。我建议将此报告给 Apple,同时继续使用变通方法,例如您的标识符。
我使用 UITableviewDiffableDataSource
和 UITableView
来显示音乐库中的歌曲。此代码运行良好:
let tracks: [MPMediaItem] = MPMediaQuery.songs().items ?? []
self.dataSource.apply(section: 0, items: tracks)
但是当我将 MPMediaItem
包装在自定义 Track struct
中时,我得到了这个错误:Fatal: supplied identifiers are not unique.
struct Track: Equatable, Hashable {
let item: MPMediaItem
var title: String? { item.title }
init(item: MPMediaItem) {
self.item = item
}
}
let items = MPMediaQuery.songs().items ?? []
let tracks: [Track] = items.map { Track(item: [=12=]) }
self.dataSource.apply(section: 0, items: tracks)
MPMediaItem
已经符合 Equatable
和 Hashable
所以我认为如果我在另一个也符合 Equatable
和 [=23 的结构中使用它应该没问题=] (Track struct
).
更新 1:apply(section:items:)
是我为了方便添加到 UITableViewDiffableDataSource
的扩展:
extension UITableViewDiffableDataSource {
func apply(section: SectionIdentifierType, items: [ItemIdentifierType], animatingDifferences: Bool = false) {
var snapshot = NSDiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType>()
snapshot.appendSections([section])
snapshot.appendItems(items)
apply(snapshot, animatingDifferences: animatingDifferences)
}
}
更新 2:在我遵守 Track
到 Identifiable
协议后它起作用了:
struct Track: Equatable, Hashable, Identifiable {
let item: MPMediaItem
let id: MPMediaEntityPersistentID
var title: String? { item.title }
init(item: MPMediaItem) {
self.item = item
self.id = item.persistentID
}
}
甚至将 title
更改为存储 属性 也没有任何错误:
struct Track: Equatable, Hashable {
let item: MPMediaItem
let title: String?
init(item: MPMediaItem) {
self.item = item
self.title = item.title
}
}
是什么让这些案例如此不同?为什么在使用 MPMediaItem
作为 Track
结构的唯一存储 属性 时出现错误?提前致谢!
我猜测 MPMediaItem 的可哈希性存在错误。这可能会导致您对所描述的两种情况得到不同的答案。在这个例子中,我会故意制作一个有问题的 NSObject:
class Dog : NSObject {
let name : String?
init(name:String?) {self.name = name}
override func isEqual(_ object: Any?) -> Bool {
if let dog = object as? Dog {
return self.name == dog.name
}
return false
}
}
struct DogHolder : Hashable {
let dog : Dog
var name : String? { dog.name }
}
这是一个测试:
var set = Set<DogHolder>()
let dh1 = DogHolder(dog:Dog(name:"rover"))
let dh2 = DogHolder(dog:Dog(name:"rover"))
set.insert(dh1)
set.insert(dh2)
print(set.count)
do {
var set = Set<Dog>()
let dh1 = Dog(name:"rover")
let dh2 = Dog(name:"rover")
set.insert(dh1)
set.insert(dh2)
print(set.count)
}
运行一遍又一遍的测试。有时我得到 1 和 2。有时我得到 2 和 1。有时我得到 1 和 1。有时我崩溃。
我不知道确切的问题是什么,但显然将 NSObject 可哈希性暴露给 Swift 的可哈希性要求会暴露该错误。我建议将此报告给 Apple,同时继续使用变通方法,例如您的标识符。