Заполните табличное представление с базой данных Firebase в реальном времени - PullRequest
1 голос
/ 22 февраля 2020

В настоящее время я получаю данные из файла json, расположенного на http-сервере

if let url = NSURL(string: "https://test.com/test") {
                do {
                    let data = try Data(contentsOf: url as URL)
                    let decoder = JSONDecoder()
                    jsonData = try decoder.decode(TestList.self, from: data)
                } catch {
                    print("error:\(error)")
                }

struct  TestList: Decodable {
        enum CodingKeys: String, CodingKey {
            case items
        }
        let items: [Item]
    }

struct Item: Decodable {
            var item_type: String?
            //...
            enum CodingKeys: String, CodingKey {
            case item_type
               //...
         }
            init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            self.item_type = try? container.decode(String.self, forKey: .mtype)
            //...        
            }
         }

Все работает нормально, но когда я переключился на базу данных реального времени firebase и получаю те же json данные

Database.database().reference().child("items").observeSingleEvent(of: .value, with: { snapshot in
            guard let value = snapshot.value else { return }
            do {
                self.jsonData = try FirebaseDecoder().decode(TestList.self, from: value)
            } catch let error {
                print(error)
            }
        })

Мой JSON:

{
  "items": [
    {
      "item_type": "Rap",
      "1": "Kastro",
      "2": "EDI",
      "3": "Noble",
      "4": ""
    },
    {
      "item_type": "Rock",
      "1": "Nickelback",
      "2": "",
      "3": "",
      "4": ""
    },
    {
      "item_type": "Pop",
      "1": "Ringo",
      "2": "",
      "3": "",
      "4": ""
    }
  ]
}

получил это сообщение:

typeMismatch (Swift.Dictionary, Swift.DecodingError.Context (codingPath: [], debugDescription: " Не словарь ", лежащий в основе ошибки: nil))

Как исправить эту ошибку?

1 Ответ

1 голос
/ 24 февраля 2020

У меня была эта проблема раньше, вот что я сделал, чтобы исправить ее. Допустим, так выглядит моя база данных. Обратите внимание на соглашение об именах, в данном примере это случай змеи.

enter image description here

Допустим, я хочу создать массив пользователей из этого снимка и заполнить мой tableView. Это сложно, потому что snapshot.value на самом деле не JSON и имеет значение Any. Вероятно, именно поэтому ваше приложение падает или в вашем случае тип не соответствует.

Давайте создадим модель для наших пользователей. Это будет выглядеть примерно так:

class User: Codable {
  var firstName: String
  var lastName: String
  var ageNumber: Int

  enum CodingKeys: String, CodingKey {
    case firstName,lastName
    case ageNumber = "age"
  }
}

Итак, позвольте мне указать кое-что по-настоящему быстро. В моей базе данных firebase пользовательские свойства выглядят как «first_name», «age» «last_name». В моей пользовательской модели это выглядит как «firstName», «ageNumber» «lastName». Поэтому мне пришлось добавить ключи кодирования из-за возраста, а не из-за имени или фамилии. Имя и фамилия меняются сами по себе, когда я устанавливаю keyCodingStrategy на моем декодере.

Вот так выглядит этот код. Оставьте несколько комментариев, чтобы лучше объяснить, что делает код.

var items = [Item]()
override func viewDidLoad() {
    super.viewDidLoad()
    // Use your database reference here.
    let ref = Database.database().reference(withPath: "users")

    ref.observe(.value) { (snapshot) in
        //First create a dict out of the snapshot value
        guard let dict = snapshot.value as? [String: Any] else { return }

        //Create a decoder this is why I don't need to chage the first_name to firstName
        //inside my coding keys
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase

        //The key is the UID and the value is what we need to create a new users
        dict.forEach { (key, value) in
            do {
                //Create new user and add it to our users array
                //We convert the value to data for the decoder with this line of code
                let testListData = try JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
                let testList = try decoder.decode(TestList.self, from: testListData)
                testList.items.forEach({ (item) in
                    self.items.append(item)
                })
            }
            catch let err {
            print(err.localizedDescription)
            }
        }
        //Reload Table View
    }
}

Надеюсь, это поможет.

Отредактировано

Таким образом, основываясь на предоставленных вами JSON. Вам придется создать свои структуры примерно так.

struct TestList: Codable {
  var items: [Item]
}

struct Item: Codable {
  var itemType: String
  var one: String
  var two: String
  var three: String
  var four: String

  enum CodingKeys: String, CodingKey {
    case itemType
    case one = "1"
    case two = "2"
    case three = "3"
    case four = "4"
  }
}

Надеюсь, это решит вашу проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...