#swift #firebase #firebase-realtime-database
# #swift #firebase #firebase-realtime-database
Вопрос:
Мой проект включает динамические данные, которые изменяются при смене контроллеров и т. Д., Поэтому в какой-то момент мои данные могут быть:
[
{
"callDescription":"TEST 16/12",
"callDuration":"5-8 Minutes",
"callID":0,
"callMade":false,
"callMade_dateTime":"false_1608151560.0",
"dateTime":1608044666,
"type":"Breakfast Call"
},
{
"callDescription":"TEST 16/12",
"callDuration":"5-8 Minutes",
"callID":0,
"callMade":false,
"callMade_dateTime":"false_1608151560.0",
"dateTime":1608044666,
"type":"Breakfast Call"
},
]
Затем выполняется фрагмент кода, и мои данные теперь
[
{
"callDescription":"TEST 16/12",
"callDuration":"5-8 Minutes",
"callID":0,
"callMade":false,
"callMade_dateTime":"false_1608151560.0",
"dateTime":1608044666,
"type":"Breakfast Call"
},
null
]
Что вызывает ошибку valueNotFound при повторном запросе данных.
Каков наилучший способ пропустить / обработать любые индексы, которые имеют значение null?
Вот мой код API:
class Service {
static let shared = Service()
let BASE_URL = "https://url.com"
func fetchClient(completion: @escaping ([Calls]) -> ()) {
guard let url = URL(string: BASE_URL) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
// handle error
if let error = error {
print("Failed to fetch data with error: ", error)
return
}
guard let data = data else {return}
do {
let myDecoder = JSONDecoder()
let calls = try myDecoder.decode([Calls].self, from: data)
completion(calls)
} catch let error {
print("Failed to create JSON with error: ", error)
}
}.resume()
}
Calls
Модель:
struct Calls: Decodable {
let callDescription, callDuration, callMade_dateTime: String
let callID: Int
let dateTime: Date
let callMade: Bool
let type: String
}
Комментарии:
1. У вас есть словарь, а не массив. Я не знаю, что такое вызовы, но, возможно, вы можете использовать
.decode([String: Calls].self,...
2. Обновил q, чтобы включить мою модель.
String: Calls
к сожалению, не сработает.3. Я не понимаю, как этот тип (вызовы) может соответствовать json в вашем вопросе
4. Я не понимаю, как ваше декодирование будет работать как таковое с образцом JSON. Это не имеет смысла. Вы пропускаете / скрываете слишком много информации, и нам сложнее определить, что не так.
5. Создайте понятный пример, но я думаю, что
[Calls].self
так и должно быть[Calls?].self
. Тогда, если вам не нужны опции, простоflatMap()
по значению.
Ответ №1:
Быстрое решение:
let calls = try myDecoder.decode([Calls].self, from: data)
completion(calls)
=>
let calls = try myDecoder.decode([Calls?].self, from: data)
completion(calls.compactMap{ $0 })
Давайте упростим пример (я начал писать ответ до того, как вы написали настоящий рабочий JSON) :
struct Custom: Codable {
let data: String
}
let jsonString = """
[{"data": "Hello"}, {"data": "world"}]
"""
let jsonString2 = """
[{"data": "Hello"}, null, {"data": "world"}]
"""
Итак, некоторые значения могут быть null внутри вашего JSON. Вот где мы можем использовать Optional .
func test(json: String) {
do {
print("Testing with [Custom].self: (json)")
let customs = try JSONDecoder().decode([Custom].self, from: json.data(using: .utf8)!)
print("Result: (customs)")
} catch {
print("Error: (error)")
}
}
func test2(json: String) {
do {
print("Testing with [Custom?].self: (json)")
let customs = try JSONDecoder().decode([Custom?].self, from: json.data(using: .utf8)!)
print("Result with optionals: (customs)")
let unwrapped = customs.compactMap { $0 }
print("Result unwrapped: (unwrapped)")
} catch {
print("Error: (error)")
}
}
test(json: jsonString)
test(json: jsonString2)
test2(json: jsonString)
test2(json: jsonString2)
Вывод:
gt;Testing with [Custom].self: [{"data": "Hello"}, {"data": "world"}]
gt;Result: [Custom(data: "Hello"), .Custom(data: "world")]
gt;Testing with [Custom].self: [{"data": "Hello"}, null, {"data": "world"}]
gt;Error: valueNotFound(Swift.KeyedDecodingContainer<.Custom.CodingKeys>, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 1", intValue: 1)], debugDescription: "Cannot get keyed decoding container -- found null value instead.", underlyingError: nil))
gt;Testing with [Custom?].self: [{"data": "Hello"}, {"data": "world"}]
gt;Result with optionals: [Optional(.Custom(data: "Hello")), Optional(.Custom(data: "world"))]
gt;Result unwrapped: [.Custom(data: "Hello"), .Custom(data: "world")]
gt;Testing with [Custom?].self: [{"data": "Hello"}, null, {"data": "world"}]
gt;Result with optionals: [Optional(.Custom(data: "Hello")), nil, Optional(.Custom(data: "world"))]
gt;Result unwrapped: [.Custom(data: "Hello"), .Custom(data: "world")]