Ios DiffableDataSource抛出“;致命:提供的标识符不唯一。”;在结构内包装MPMediaItem时
我使用Ios DiffableDataSource抛出“;致命:提供的标识符不唯一。”;在结构内包装MPMediaItem时,ios,swift,diffabledatasource,Ios,Swift,Diffabledatasource,我使用UITableView diffabledatasource和UITableView来显示音乐库中的歌曲。该代码运行良好: let tracks:[MPMediaItem]=MPMediaQuery.songs().items??[] self.dataSource.apply(节:0,项:跟踪) 但是,当我将MPMediaItem包装到自定义Track结构中时,出现了以下错误:致命:提供的标识符不唯一。 struct Track:equalable,Hashable{ let项目:MP
UITableView diffabledatasource
和UITableView
来显示音乐库中的歌曲。该代码运行良好:
let tracks:[MPMediaItem]=MPMediaQuery.songs().items??[]
self.dataSource.apply(节:0,项:跟踪)
但是,当我将MPMediaItem
包装到自定义Track结构中时,出现了以下错误:致命:提供的标识符不唯一。
struct Track:equalable,Hashable{
let项目:MPMediaItem
变量标题:字符串?{item.title}
初始化(项目:MPMediaItem){
self.item=项目
}
}
让items=MPMediaQuery.songs().items??[]
let tracks:[Track]=items.map{Track(item:$0)}
self.dataSource.apply(节:0,项:跟踪)
MPMediaItem
已经符合了equalable
和Hashable
的要求,因此我认为如果我在另一个同样符合equalable
和Hashable
的结构中使用它,应该没问题(跟踪结构
)
更新1:apply(部分:items:)
是我添加到UITableViewDiffableDataSource
的扩展,以方便:
扩展UITableViewDiffableDataSource{
func apply(节:SectionIdentifierType,项:[ItemIdentifierType],动画差异:Bool=false){
var snapshot=NSDiffableDataSourceSnapshot()
snapshot.appendSections([节])
snapshot.appendItems(项目)
应用(快照、动画差异:动画差异)
}
}
更新2:在我符合跟踪
到可识别
协议后,它起作用了:
struct Track:equalable、Hashable、Identifiable{
let项目:MPMediaItem
let id:MPMediaEntityPersistentID
变量标题:字符串?{item.title}
初始化(项目:MPMediaItem){
self.item=项目
self.id=item.persistentID
}
}
甚至将标题更改为存储属性也可以正常工作,没有任何错误:
struct Track:equalable,Hashable{
let项目:MPMediaItem
标题:字符串?
初始化(项目:MPMediaItem){
self.item=项目
self.title=item.title
}
}
是什么让这些案例如此不同?为什么在使用MPMediaItem
作为Track
结构的唯一存储属性时会出现错误?提前谢谢 我猜MPMediaItem的哈希性中有一个bug。这可能会导致您在所描述的两种情况下得到不同的答案。在本例中,我将故意创建一个buggy 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)
}
var set=set()
设dh1=狗托(狗:狗(名称:“漫游者”))
设dh2=狗托(狗:狗(名称:“漫游者”))
set.insert(dh1)
set.insert(dh2)
打印(设置计数)
做{
var set=set()
让dh1=狗(名称:“漫游者”)
让dh2=狗(名称:“漫游者”)
set.insert(dh1)
set.insert(dh2)
打印(设置计数)
}
反复运行测试。有时我得到1和2。有时我得到2和1。有时我得到1和1。有时我会撞车
我不知道确切的问题是什么,但很明显,将NSObject哈希性暴露在Swift的哈希性要求之下会暴露出错误。我建议向苹果公司报告这一点,同时继续使用一种解决方法,比如您的标识符。我猜MPMediaItem的哈希功能中有一个bug。这可能会导致您在所描述的两种情况下得到不同的答案。在本例中,我将故意创建一个buggy 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)
}
var set=set()
设dh1=狗托(狗:狗(名称:“漫游者”))
设dh2=狗托(狗:狗(名称:“漫游者”))
set.insert(dh1)
set.insert(dh2)
打印(设置计数)
做{
var set=set()
让dh1=狗(名称:“漫游者”)
让dh2=狗(名称:“漫游者”)
set.insert(dh1)
set.insert(dh2)
打印(设置计数)
}
反复运行测试。有时我得到1和2。有时我得到2和1。有时我得到1和1。有时我会撞车
我不知道确切的问题是什么,但很明显,将NSObject哈希性暴露在Swift的哈希性要求之下会暴露出错误。我建议将此情况报告给苹果公司,同时继续使用诸如您的标识符之类的解决方法。对不起,我忘了这一点。我已经更新了我的问题。谢谢好吧,现在我很好奇。如果您完全省略title属性会怎么样?嗨@matt,我用两个有效的解决方案再次更新了我的问题。但是我不知道为什么只使用MPMediaItem
作为存储属性,而不使用任何其他存储属性,如id
和title
抛出错误。您应该通过哈希函数确认哈希值抱歉,我忘了这一点。我已经更新了我的问题。谢谢好吧,现在我很好奇。如果您完全省略title属性会怎么样?嗨@matt,我用两个有效的解决方案再次更新了我的问题。但是我不知道为什么只使用MPMediaItem
作为存储属性,而不使用任何其他存储属性,如id
和title
抛出错误。您应该通过哈希函数确认哈希值hash
的默认NSObject
实现使用对象的指针值。因此,如果您重写isEqual
以检查基于数据成员的相等性,则还必须重写hash
,否则您将违反A==B的要求→ 散列(A)=散列(B)
。也许苹果的工程师们在为MPMediaItem
@TamásZahola Good theory重写isEqual
时也犯了同样的错误;当然,我确实想到过这样的事情,但不管它是什么,我都无法证明它。NSObject
的默认hash
实现使用对象的指针值。因此,如果覆盖