Доступ к объекту данных по идентификатору

#swift #swiftui

#swift #swiftui

Вопрос:

У меня есть следующие структуры, определенные в соответствии с примером SwiftUI в Apple.

 struct Cat: Hashable, Codable, Identifiable {
    let id: Int
    let name: String
    let audio: [Int]? // list of audio of cat sound
}

struct CatAudio: Hashable, Codable, Identifiable {
    let id: Int
    let filename: String
}
 

Затем я хотел бы получить доступ к аудио, а затем передать его в представлении.

У меня есть данные json, подобные этому:

 [
  {
    "id": 55,
    "name": "meow",
    "audio": [6,5]
  },
  {
    "id": 3,
    "name": "meowmeow",
    "audio": [2]
  }
]
 

audioData.json

 [
  {
    "id": 5,
    "filename": "5.wav"
  },
  {
    "id": 2,
    "filename": "2.wav"
  },
  {
    "id": 6,
    "filename": "6.wav"
  }
]
 

Файлы json успешно загружены.

 @Published var cats: [Cat] = load("CatData.json")
@Published var catAudios: [CatAudio] = load("CatAudio.json")
 

Затем я попытался получить аудиообъект из данных моей модели среды:

 @EnvironmentObject var modelData: ModelData
 

и затем я хочу получить соответствующий аудиообъект cat. но мне не удалось этого сделать, поскольку я не знаю, как использовать «Идентификатор» для его получения.

Пример:

Предположим, что я получил объект cat из своей модели:

  let cat = modelData.cats[0]
 

Затем я хочу получить его аудиоданные в соответствии с идентификатором, хранящимся в его списке аудиозаписей

 let catAudio = modelData.catAudios[cat.audio[0]!] // exception here
 

Я обнаружил, что это связано с тем, что порядок массива может не соответствовать «Идентификатору». Я хочу использовать «Идентификатор» вместо порядка массива, чтобы получить элемент.
Как я могу это сделать?

========

Я попытался написать функцию для получения списка CatAudio кота. Я также сделал аудио необязательным.

 func getAudio(cat: Cat) -> [CatAudio] {
        return cat.audio.compactMap{id in catAudio.filter { $0.id==id } }
}
 

Но он жалуется и говорит, что не может преобразовать значение типа [CatAudio] в тип результата закрытия ‘CatAudio’

Я запутался с этим.

Ответ №1:

Вам необходимо использовать функции высокого порядка для сопоставления значений идентификаторов в audio массиве с элементами в массиве CatAudio

Предполагая, что 2 массива и выбранный объект Cat

 var cats: [Cat] = ...
var catAudios: [CatAudio] = ...

let cat = cats[0]
 

Чтобы выбрать один звук для одного идентификатора

 if let firstId = cat.audio?.first {
    let audio = catAudios.first { $0.id == firstId}
}
 

Чтобы получить массив всех CatAudio для cat объекта

 if let array = cat.audio {
    let values = array.compactMap { id in catAudios.filter { $0.id == id }}
}
 

Код был бы проще, если audio бы массив не был необязательным, есть ли причина для его объявления необязательным?

Комментарии:

1. У некоторых cat нет записи голоса, поэтому необязательно. Тем не менее, я могу изменить его на массив размером 0, это нормально. Как код может быть проще, если это необязательно ?!

2. Эффективен ли приведенный выше код, если у меня много кошек? Представьте, что это итератор, который перебирает все объекты в списке и проверяет один за другим?

3. @user6539552 С необязательным массивом вы можете пропустить некоторые if let... , которые могут сделать код короче и понятнее, но это не обязательно. Если у вас много объектов Cat, было бы неплохо превратить массив CatAudio в словарь с идентификатором в качестве ключа для более быстрого поиска.

4. Я новичок в разработке. Я только следую руководству в Apple, оно загружает данные в список из Json. Вы имеете в виду, что я должен изменить код в этот момент, не используя array для хранения данных Json? В чем будет разница, если я использую dict для хранения элементов?

5. я попытался написать функцию для получения списка объектов CatAudio с помощью фильтра, но, похоже, это не работает.. Я должен сделать CatAudio необязательным. (Я отредактировал свой вопрос, чтобы включить код)