#json #swift #realm
#json #swift #realm
Вопрос:
Итак, у меня есть некоторые JSON-данные, которые я извлекаю из API с помощью alamofire. Когда данные возвращаются, структура выглядит следующим образом
{
"sneakers" : {
"brands" : {
"Adidas" : [ {
"brand" : "adidas",
"category" : "lifestyle",
"colorway" : "Cream White/Cream White/Core White",
"description" : "First released on April 29, 2017, the Yeezy Boost 350 V2 ‘Cream White’ combines a cream Primeknit upper with tonal cream SPLY 350 branding, and a translucent white midsole housing full-length Boost. Released again in October 2018, this retro helped fulfill Kanye West’s oft-repeated ‘YEEZYs for everyone’ Twitter mantra, as adidas organized the biggest drop in Yeezy history by promising pre-sale to anyone who signed up on the website. Similar to the first release, the ‘Triple White’ 2018 model features a Primeknit upper, a Boost midsole and custom adidas and Yeezy co-branding on the insole.",
"designer" : "Kanye West",
"imagesrc" : "https://image.goat.com/crop/1250/attachments/product_template_additional_pictures/images/014/822/695/original/116662_03.jpg.jpeg",
"maincolor" : "White",
"name" : "Yeezy Boost 350 V2 'Cream White / Triple White'",
"nickname" : "Cream White / Triple White",
"price" : "Buy New - $220",
"productlink" : "$190YEEZY BOOST 350 V2 'CREAM WHITE / TRIPLE WHITE'",
"productlinkhref" : "https://www.goat.com/sneakers/yeezy-boost-350-v2-cream-white-cp9366",
"releasedate" : "2017-04-29",
"silhouette" : "Yeezy Boost 350",
"technology" : "Boost",
"webscraperorder" : "1554084922-147",
"webscraperstarturl" : "https://www.goat.com/sneakers"
}
]
}
}
}
Где потенциально может быть больше брендов (Nike, Air Jordan), у которых под ними больше кроссовок. Используя протокол Swift Decodable, я смог правильно проанализировать данные JSON в объекты, которые легко читаются любым пользователем. Этот код можно увидеть ниже.
import Foundation
import RealmSwift
import Realm
struct Sneaker: Decodable {
var sneakers : Sneakers
}
struct Sneakers: Decodable {
let brands: Shoe
}
struct Shoe: Decodable {
let adidas: [SneakerInfo]
let nike: [SneakerInfo]
let airjordan: [SneakerInfo]
let vans: [SneakerInfo]
enum CodingKeys: String, CodingKey {
case adidas = "Adidas"
case nike = "Nike"
case airjordan = "Air Jordan"
case vans = "Vans"
}
}
struct SneakerInfo: Decodable {
let brand, category, colorway, description: String?
let designer: String?
let imagesrc: String?
let maincolor, name, nickname, price: String?
let productlink: String?
let productlinkhref: String?
let releasedate, silhouette, technology, webscraperorder: String?
let webscraperstarturl: String?
enum CodingKeys: String, CodingKey {
case brand, category, colorway, description, designer, imagesrc, maincolor, name, nickname, price, productlink, productlinkhref, releasedate, silhouette, technology,webscraperorder,webscraperstarturl
}
}
В настоящее время я пытаюсь перенести этот же код, чтобы быть готовым к использованию с realm и codable, но я продолжаю получать ошибки.
Моя проблема заключается в жалобах на мою реализацию и инициализации. Я включу класс ниже. Я застрял на этом весь день.
import Foundation
import Realm
import RealmSwift
@objcMembers class SneakerTemp: Object, Decodable {
dynamic var sneaker: SneakersTemp
enum CodingKeys: String, CodingKey {
case sneaker
}
required init()
{
super.init()
}
override static func primaryKey() -> String?
{
return UUID().uuidString
}
required init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
sneaker = try container.decode(SneakersTemp.self, forKey: .sneaker)
super.init()
}
required init(value: Any, schema: RLMSchema)
{
super.init(value: value, schema: schema)
}
required init(realm: RLMRealm, schema: RLMObjectSchema)
{
super.init(realm: realm, schema: schema)
}
}
@objcMembers class SneakersTemp: Object, Decodable {
dynamic var brands:ShoeTemp
enum CodingKeys: String, CodingKey {
case brands
}
required init()
{
super.init()
}
override static func primaryKey() -> String?
{
return UUID().uuidString
}
required init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
brands = try container.decode(ShoeTemp.self, forKey: .brands)
super.init()
}
required init(value: Any, schema: RLMSchema)
{
super.init(value: value, schema: schema)
}
required init(realm: RLMRealm, schema: RLMObjectSchema)
{
super.init(realm: realm, schema: schema)
}
}
@objcMembers class ShoeTemp: Object, Decodable {
let adidas = RealmSwift.List<SneakerInfoTemp>()
let nike = RealmSwift.List<SneakerInfoTemp>()
let airjordan = RealmSwift.List<SneakerInfoTemp>()
let vans = RealmSwift.List<SneakerInfoTemp>()
enum CodingKeys: String, CodingKey {
case adidas = "Adidas"
case nike = "Nike"
case airjordan = "Air Jordan"
case vans = "Vans"
}
required init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
adidas = try container.decode(String.self, forKey: .adidas)
nike = try container.decode(String.self, forKey: .nike)
airjordan = try container.decode(String.self, forKey: .airjordan)
vans = try container.decode(String.self, forKey: .vans)
super.init()
}
required init()
{
super.init()
}
override static func primaryKey() -> String?
{
return UUID().uuidString
}
required init(value: Any, schema: RLMSchema)
{
super.init(value: value, schema: schema)
}
required init(realm: RLMRealm, schema: RLMObjectSchema)
{
super.init(realm: realm, schema: schema)
}
}
@objcMembers class SneakerInfoTemp: Object, Decodable {
dynamic var brand: String?
dynamic var category: String?
dynamic var colorway: String?
dynamic var descriptionTemp: String?
dynamic var designer: String?
dynamic var imagesrc: String?
dynamic var maincolor: String?
dynamic var name: String?
dynamic var nickname: String?
dynamic var price: String?
dynamic var productlink: String?
dynamic var productlinkhref: String?
dynamic var releasedate: String?
dynamic var silhouette: String?
dynamic var technology: String?
dynamic var webscraperorder: String?
dynamic var webscraperstarturl: String?
enum CodingKeys: String, CodingKey {
case brand, category, colorway, designer, imagesrc, maincolor, name, nickname, price, productlink, productlinkhref, releasedate, silhouette, technology,webscraperorder,webscraperstarturl
case descriptionTemp = "description"
}
required init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
brand = try container.decode(String.self, forKey: .brand)
category = try container.decode(String.self, forKey: .category)
colorway = try container.decode(String.self, forKey: .colorway)
descriptionTemp = try container.decode(String.self, forKey: .descriptionTemp)
designer = try container.decode(String.self, forKey: .designer)
imagesrc = try container.decode(String.self, forKey: .imagesrc)
maincolor = try container.decode(String.self, forKey: .maincolor)
name = try container.decode(String.self, forKey: .name)
nickname = try container.decode(String.self, forKey: .nickname)
price = try container.decode(String.self, forKey: .price)
productlink = try container.decode(String.self, forKey: .productlink)
productlinkhref = try container.decode(String.self, forKey: .productlinkhref)
releasedate = try container.decode(String.self, forKey: .releasedate)
silhouette = try container.decode(String.self, forKey: .silhouette)
technology = try container.decode(String.self, forKey: .technology)
webscraperorder = try container.decode(String.self, forKey: .webscraperorder)
webscraperstarturl = try container.decode(String.self, forKey: .webscraperstarturl)
super.init()
}
required init()
{
super.init()
}
required init(value: Any, schema: RLMSchema)
{
super.init(value: value, schema: schema)
}
required init(realm: RLMRealm, schema: RLMObjectSchema)
{
super.init(realm: realm, schema: schema)
}
}
Основная ошибка заключается
Свойство ‘self.sneaker’ не инициализировано при вызове super.init
и
Свойство ‘self.brands’ не инициализировано при вызове super.init
Ответ №1:
В классе необходимо инициализировать sneaker
и brands
или сделать необязательными, что инициализирует их равными нулю. Структуры имеют инициализаторы memberwise по умолчанию.
import Foundation
import Realm
import RealmSwift
class SneakerTemp: Object, Decodable {
@objc dynamic var id = UUID().uuidString
@objc dynamic var sneaker = SneakersTemp()
// or @objc dynamic var sneaker: SneakersTemp?
override static func primaryKey() -> String? {
return "id"
}
}
class SneakersTemp: Object, Decodable {
@objc dynamic var id = UUID().uuidString
@objc dynamic var brands = ShoeTemp()
// or @objc dynamic var brands: ShoeTemp?
override static func primaryKey() -> String? {
return "id"
}
}
class ShoeTemp: Object, Decodable {
@objc dynamic var id = UUID().uuidString
let adidas = List<SneakerInfoTemp>()
let nike = List<SneakerInfoTemp>()
let airjordan = List<SneakerInfoTemp>()
let vans = List<SneakerInfoTemp>()
override static func primaryKey() -> String? {
return "id"
}
enum CodingKeys: String, CodingKey {
case adidas = "Adidas"
case nike = "Nike"
case airjordan = "Air Jordan"
case vans = "Vans"
}
}
class SneakerInfoTemp: Object, Decodable {
@objc dynamic var brand: String?
@objc dynamic var category: String?
@objc dynamic var colorway: String?
@objc dynamic var descriptionTemp: String?
@objc dynamic var designer: String?
@objc dynamic var imagesrc: String?
@objc dynamic var maincolor: String?
@objc dynamic var name: String?
@objc dynamic var nickname: String?
@objc dynamic var price: String?
@objc dynamic var productlink: String?
@objc dynamic var productlinkhref: String?
@objc dynamic var releasedate: String?
@objc dynamic var silhouette: String?
@objc dynamic var technology: String?
@objc dynamic var webscraperorder: String?
@objc dynamic var webscraperstarturl: String?
enum CodingKeys: String, CodingKey {
case brand, category, colorway, designer, imagesrc, maincolor, name, nickname, price, productlink, productlinkhref, releasedate, silhouette, technology,webscraperorder,webscraperstarturl
case descriptionTemp = "description"
}
}
Комментарии:
1. Да, я это исправил, но теперь он выдает ошибку в отношении моего первичного ключа
2. извините, я забыл добавить это
3. Я продолжаю получать эту ошибку, завершающую работу приложения из-за неперехваченного исключения ‘RLMException’, причина: ‘Свойство первичного ключа ‘E81CE86C-B176-4920-AF87-06E3E83CB803’ не существует для объекта ‘SneakerInfoTemp»
4. Хорошо, вот так.
5. я понял это