0

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

let tracks: [MPMediaItem] = MPMediaQuery.songs().items ?? []
self.dataSource.apply(section: 0, items: tracks)

但是当我包裹MPMediaItem在一个 custom中时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已经符合Equatable,所以我认为如果我在另一个也符合and ( )Hashable的结构中使用它应该没问题。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为 store 属性也可以正常工作:

struct Track: Equatable, Hashable {
  let item: MPMediaItem

  let title: String?

  init(item: MPMediaItem) {
    self.item = item
    self.title = item.title
  }
}

是什么让这些案例之间如此不同?为什么在MPMediaItem用作结构的唯一存储属性时会出现错误Track?提前致谢!

4

1 回答 1

2

我猜测 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,同时继续使用您的标识符等解决方法。

于 2020-04-11T16:54:55.413 回答