DiffableDataSource выдает «Фатальный: предоставленные идентификаторы не являются уникальными». при переносе MPMediaItem внутри структуры - PullRequest
0 голосов
/ 10 апреля 2020

Я использовал UITableviewDiffableDataSource с UITableView для отображения песен из библиотеки musi c. Этот код работал нормально:

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 уже соответствует Equatable и Hashable, поэтому я думаю, что будет хорошо, если я использую его в другой структуре, которая также соответствует Equatable и Hashable (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? Заранее спасибо!

1 Ответ

1 голос
/ 11 апреля 2020

Я собираюсь догадаться, что есть ошибка в хэш-возможности 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. Иногда я делаю sh.

Я не знаю, в чем именно заключается проблема, но очевидно, что подвергание HSObject хэшируемости требованиям Swift хэшируемости выявляет ошибку. Я бы посоветовал сообщить об этом Apple и тем временем продолжать использовать обходной путь, такой как ваш идентификатор.

...