DiffableDataSource引发“致命:提供的标识符不是唯一的。”将MPMediaItem包装在结构中时

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DiffableDataSource引发“致命:提供的标识符不是唯一的。”将MPMediaItem包装在结构中时相关的知识,希望对你有一定的参考价值。

我用UITableviewDiffableDataSourceUITableView来显示音乐库中的歌曲。这段代码运行良好:

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: $0) 
self.dataSource.apply(section: 0, items: tracks)

[MPMediaItem已经符合EquatableHashable,所以我认为如果我在也符合EquatableHashableTrack 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,同时继续使用替代方法,例如您的标识符。

以上是关于DiffableDataSource引发“致命:提供的标识符不是唯一的。”将MPMediaItem包装在结构中时的主要内容,如果未能解决你的问题,请参考以下文章

DiffableDataSource - 无动画,但在删除操作期间闪烁

UICollectionViewController + diffableDataSource - 当您的手指仍在其上时,单元格不会突出显示

DiffableDataSource CollectionView 在部分中不返回任何项目

DiffableDataSource 抛出“致命:提供的标识符不是唯一的。”将 MPMediaItem 包装在结构中时

UITableView diffable 数据源

iOS 14 UICollectionViewCell 相关