Key Relationship Based on the Swift Decodable Object Attributes

Given JSON:

[{
        "name": "TV",
        "room": "Living Room"
    },
    {
        "name": "LightBulb 1",
        "room": "Living Room"
    }
]


struct Room: Decodable {
  let name: String
  let devices: [Device]
}
struct Device: Decodable {
  let name: String
}

How can I use the Swift 4 Decodable JSON decoding method to correctly get the serialization of the model? I want to create rooms for each unique row in the roomdevice attribute and add these devices to the list of devices in this room.

One way is to simply compare this without regard to the room, and then analyze this attitude after I have received the entire list of Devices, just skipping and creating rooms on demand when I iterate over it. But this is not like a way The Swift 4™to do it. Is there a smarter way?

+4
2

- "Swift 4 Decodable JSON" try JSONDecoder().decode([Room].self, from: jsonData). , , , , JSONDecoder JSON Room(from: Decoder) . , , JSON.

Decodable, JSON, Room, .

, Xcode:

import UIKit

struct Room {
    let name:    String
    var devices: [Device]

    fileprivate struct DeviceInRoom: Decodable {
        let name: String
        let room: String
    }

    static func rooms(from data: Data) -> [Room]? {
        return (try? JSONDecoder().decode([DeviceInRoom].self, from: data))?.rooms()
    }
}
struct Device {
    let name: String
}

fileprivate extension Array where Element == Room.DeviceInRoom {
    func rooms() -> [Room] {
        var rooms = [Room]()
        self.forEach { deviceInRoom in
            if let index = rooms.index(where: { $0.name == deviceInRoom.room }) {
                rooms[index].devices.append(Device(name: deviceInRoom.name))
            } else {
                rooms.append(Room(name: deviceInRoom.room, devices: [Device(name: deviceInRoom.name)]))
            }
        }
        return rooms
    }
}

let json = """
[
  {
    "name": "TV",
    "room": "Living Room"
  },
  {
    "name": "LightBulb 1",
    "room": "Living Room"
  }
]
"""

if let data  = json.data(using: .utf8),
   let rooms = Room.rooms(from: data) {

    print(rooms)
}

- , :

import UIKit

struct Room {
    let name:    String
    var devices: [Device]
}

struct Device {
    let name: String
}

struct RoomContainer: Decodable {

    let rooms: [Room]

    private enum CodingKeys: String, CodingKey {
        case name
        case room
    }

    init(from decoder: Decoder) throws {
        var rooms = [Room]()
        var objects = try decoder.unkeyedContainer()
        while objects.isAtEnd == false {
            let container  = try objects.nestedContainer(keyedBy: CodingKeys.self)
            let deviceName = try container.decode(String.self, forKey: .name)
            let roomName   = try container.decode(String.self, forKey: .room)
            if let index = rooms.index(where: { $0.name == roomName }) {
                rooms[index].devices.append(Device(name: deviceName))
            } else {
                rooms.append(Room(name: roomName, devices: [Device(name: deviceName)]))
            }
        }
        self.rooms = rooms
    }
}

let json = """
[
  {
    "name": "TV",
    "room": "Living Room"
  },
  {
    "name": "LightBulb 1",
    "room": "Living Room"
  }
]
"""

if let data  = json.data(using: .utf8),
   let rooms = (try? JSONDecoder().decode(RoomContainer.self, from: data))?.rooms {

    print(rooms)
}

. try? . , - JSONDecoder , , !:)

+3

Eivind, , 2 ... JSON - , JSON - Swift. JSON, , - , , , - JSON, Swift. , Plain Ol Swift Objects (POSOs) , , POSO Decodables , . , , , , pure-Swift.

Apple JSON

JSON Swift

, , .

, . , snake_case JSON camelCase , JSON Swift- API, Mirror.

, , , Swift, . JSON, . , , . . , .

import Foundation
import UIKit

struct RoomJSON
{
    let name: String
    let room: String
}

struct Room
{
    let name: String
    let devices: [Device]
}

struct Device
{
    let name: String
}

extension RoomJSON: Decodable {
    enum RoomJSONKeys: String, CodingKey
    {
        case name = "name"
        case room = "room"
    }

    init(from decoder: Decoder) throws
    {
        let container = try decoder.container(keyedBy: RoomJSONKeys.self)
        let name: String = try container.decode(String.self, forKey: .name)
        let room: String = try container.decode(String.self, forKey: .room)

        self.init(name: name, room: room)
    }
}

let json = """
[{
    "name": "TV",
    "room": "Living Room"
 },
 {
    "name": "LightBulb 1",
    "room": "Living Room"
 }]
""".data(using: .utf8)!

var rooms: [RoomJSON]?
do {
    rooms = try JSONDecoder().decode([RoomJSON].self, from: json)
} catch {
    print("\(error)")
}

if let rooms = rooms {
    for room in rooms {
        print(room)
    }
}
+2

Source: https://habr.com/ru/post/1685465/


All Articles