Как разобрать локальные JSON данные в Swift? - PullRequest
1 голос
/ 04 августа 2020

Как анализировать локальные JSON данные где вложенное (необязательное) свойство такое же, как и основное.

Данные элементов могут быть доступны или могут быть недоступны.

struct Category: Identifiable, Codable {
    let id: Int
    let name: String
    let image: String
    var items: [Category]?   
}

Я использую обычное расширение Bundle для анализа JSON данных.

extension Bundle {

    func decode<T: Codable>(_ file: String) -> T {
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Failed to locate \(file) in bundle.")
        }

        guard let data = try? Data(contentsOf: url) else {
            fatalError("Failed to load \(file) from bundle.")
        }

        let decoder = JSONDecoder()

        let formatter = DateFormatter()
        formatter.dateFormat = "y-MM-dd"
        decoder.dateDecodingStrategy = .formatted(formatter)
    
        guard let loaded = try? decoder.decode(T.self, from: data) else {
            fatalError("Failed to decode \(file) from bundle.")
        }
        return loaded
    }
}

Например, для данных:

[
    {
        "id": 1,
        "name": "Apple",
        "image": "img_url",
        "items" : [
            {
                "id": 1,
                "name": "iPhone",
                "image": "img_url",
                "items" : [
                    {
                        "id": 1,
                        "name": "iPhone 11 Pro",
                        "image": "img_url"
                    },
                    {
                        "id": 2,
                        "name": "iPhone 11 Pro Max",
                        "image": "img_url"
                    }    
                ]
            },
            {
                "id": 2,
                "name": "iPad",
                "image": "img_url",
                "items" : [
                    {
                        "id": 1,
                        "name": "iPad mini",
                        "image": "img_url"
                    },
                    {
                        "id": 2,
                        "name": "iPad Air",
                        "image": "img_url"
                    },
                    {
                        "id": 3,
                        "name": "iPad Pro",
                        "image": "img_url"
                    }
                ]
            }
        ]
    },
    {
        "id": 2,
        "name": "Samsung",
        "image": "img_url",
        "items" : [
            {
                "id": 1,
                "name": "Phone",
                "image": "img_url"
            },
            {
                "id": 2,
                "name": "Tablet",
                "image": "img_url"
            }
        ]
    }
]

1 Ответ

3 голосов
/ 04 августа 2020

Вложенность здесь не проблема, вы столкнулись с Array из Content s. поэтому вы должны передать [Content] в decoder, например:

let jsonDecoder = JSONDecoder()
try! jsonDecoder.decode([Category].self, from: json)

? Property Wrapper

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

@propertyWrapper struct BundleFile<DataType: Decodable> {
    let name: String
    let type: String = "json"
    let fileManager: FileManager = .default
    let bundle: Bundle = .main
    let decoder = JSONDecoder()

    var wrappedValue: DataType {
        guard let path = bundle.path(forResource: name, ofType: type) else { fatalError("Resource not found") }
        guard let data = fileManager.contents(atPath: path) else { fatalError("File not loaded") }
        return try! decoder.decode(DataType.self, from: data)
    }
}

Теперь вы можете иметь любое свойство, которое должно быть загружено из файла в Bundle, например:

@BundleFile(name: "MyFile")
var contents: [Content]

Обратите внимание, что, поскольку свойство должно быть загружено из пакета, я поднял FatalError. Потому что за эти ошибки должен нести ответственность только разработчик во время кода (а не во время выполнения).

...