#ios #json #swift #api #uikit
Вопрос:
Я пытаюсь отфильтровать пустые и нулевые значения из api в формате json в swift(UIKit). Полные возвращаемые данные выглядят так, как показано ниже, но иногда могут содержать нулевые или пустые значения в characteristic
ключе. Всегда будет одинаковое количество ключей.
//Cat { "breedname": "Persian", "picture": "https://catimage.random.png", "characteristic1": "Shy", "characteristic2": "Hungry all the time" "characteristic3": "Likes apples" "characteristic4": "Grey color" "characteristic5": "likes chin scratches" } { "breedname": "Bengal", "picture": "https://catimage.random.png", "characteristic1": "Active", "characteristic2": "Adventurous" "characteristic3": "" "characteristic4": "" "characteristic5": "" } { "breedname": "ragdoll", "picture": "https://catimage.random.png", "characteristic1": "Fiestey", "characteristic2": "sharp claws" "characteristic3": null "characteristic4": null "characteristic5": null }
Чтобы отфильтровать пустые и пустые значения перед отображением в пользовательском интерфейсе, у меня есть декодируемый класс, как показано ниже, и пользовательский класс инициализации с decodeifPresent
методом, который изменяет значения null на nill. Однако для пустых значений я только что создал метод, который преобразует пустые строковые значения в ноль. Я не уверен, есть ли лучшие способы обработки пустых и пустых данных и их фильтрации? Я ссылаюсь на все декодируемые ключи в пользовательском интерфейсе, поэтому я не могу просто удалить сами ключи.
struct Cat: Decodable { let breedName: String let picture: String let characteristic1 : String? let characteristic2 : String? let characteristic3 : String? let characteristic4 : String? let characteristic5 : String? enum CodingKeys: String, CodingKey { case breedName case picture case characteristic1 case characteristic2 case characteristic3 case characteristic4 case characteristic5 } func checkEmpty(s: String?) -gt; String? { if s == "" { return nil } return s } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.breedName= try container.decode(String.self, forKey: .breedName) self.picture = try container.decode(String.self, forKey: .picture) self.characteristic1 = try container.decodeIfPresent(String.self, forKey: .characteristic1) self.characteristic2 = try container.decodeIfPresent(String.self, forKey: .characteristic2) self.characteristic3 = try container.decodeIfPresent(String.self, forKey: .characteristic3) self.characteristic4 = try container.decodeIfPresent(String.self, forKey: .characteristic4) self.characteristic5 = try container.decodeIfPresent(String.self, forKey: .characteristic5) self.characteristic1 = checkEmpty(s: self.characteristic1) self.characteristic2 = checkEmpty(s: self.characteristic2) self.characteristic3 = checkEmpty(s: self.characteristic3) self.characteristic4 = checkEmpty(s: self.characteristic4) self.characteristic5 = checkEmpty(s: self.characteristic5)
Ответ №1:
Одним из решений является проверка пустоты в функции, определенной в расширении к строке
extension String { func emptyAsNil() -gt; String? { self.isEmpty ? nil : self } }
Тогда вы могли бы сделать все за один шаг в init
self.characteristic1 = try container.decodeIfPresent(String.self, forKey: .characteristic1)?.emptyAsNil()
Но, возможно, лучшим решением будет собрать все эти свойства в коллекцию, такую как массив или словарь. Здесь я выбрал массив
struct Cat: Decodable { let breedName: String let picture: String var characteristics: [String] }
а затем в инициализации мы добавляем в массив только ненулевые, непустые значения
if let value = try container.decodeIfPresent(String.self, forKey: .characteristic1), !value.isEmpty { characteristics.append(value) }
или другой способ-перебирать клавиши
let keys: [CodingKeys] = [.characteristic1, .characteristic2, .characteristic3, .characteristic4, .characteristic5] for key in keys { if let value = try container.decodeIfPresent(String.self, forKey: key), !value.isEmpty { characteristics.append(value) } }