Парсинг JSON с помощью Codable

swift
json
ios

#1

Добрый день, не понимаю как распарсить данный JSON без использования кучи классов, а именно с помощью CodingKey, чтоб на выходе получился массив друзей. Запрос отправляю так AF.request(“https://api.vk.com/method/friends.get”, method: .get,
parameters: [“access_token”: Session.instance.token, “v”:5.107, “fields”: “photo_50,nickname,online”]).responseData(completionHandler: { (response) in
guard let data = response.value else { return }
do {
let friends = try JSONDecoder().decode([User].self, from: data)
print(friends)
} catch {
print(error)
}
})
сам JSON:
{“response”:{“count”:83,“items”:[{“id”:7934694,“first_name”:“Алла”,“last_name”:“Иванова”,“is_closed”:true,“can_access_closed”:true,“nickname”:“Зачеркнем прошло”,“photo_50”:“https://sun9-15.userapi.com/c855732/v855732802/239eac/it5QvuGXU-s.jpg?ava=1",“online”:0,“track_code”:“05e2bb11szExxPcfsiLcMl7pghphbiv_M-MjMkDByODnrbyutUrSUgOm9RCzdNlpajYEsVoXKP9ahg”},{“id”:17104712,“first_name”:“Анютка”,“last_name”:“Ганюня”,“is_closed”:true,“can_access_closed”:true,“nickname”:"",“photo_50”:“https://sun9-55.userapi.com/c849424/v849424309/c7679/TZa-g9CfoP0.jpg?ava=1”,“online”:0,“track_code”:“d4cf2bc0MRhtIf8bpz-O52kJBy2SHuk-bIbeWsFXyfUouLL39J5Qe1VKrUnwa9uyWeLqirp-5Cl347A”},{“id”:20693385,“first_name”:“Лия”,“last_name”:“Сашина”,“is_closed”:true,“can_access_closed”:true,“nickname”:"",“photo_50”:“https://sun9-65.userapi.com/c834403/v834403918/a314/A7QeezXBGCU.jpg?ava=1”,“online”:0,“track_code”:"9c5b0d926nULNxEJ7zHSOXeMcmDc_D4cOQCtKZmztJGnEvUoQSmLFm8KFFztMNEzTWCfx_ScMwsiZcM”}]}}


#2

попробуйте вместо responseData - responseJson
и что у вас в принт уходит?


#3

typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: “Expected to decode Array<Any> but found a dictionary instead.”, underlyingError: nil))
я не понимаю как достучаться именно до юзеров


#4


сейчас я пытаюсь сделать так, что нужно изменить?


#5

вам промежуточная модель нужна для response

struct Response: Codable {
    var response: ResponseInfo
}

struct ResponseInfo: Codable {
    var count: Int
    var items: [User]
}

#6

так у меня работает, но я хотел сделать без использования сторонних моделей, а чтоб руками указать, откуда нужно доставать значения


#7

так у вас и так одна модель используется


#8

можно ли сделать так, чтоб не использовать промежуточные модели, которые вы мне предложили, а чтоб был просто класс User и при его инициализации доставались все значения?


#9

в вашем варианте так и сделано, что вас не устраивает?


#10

то, что оно не отрабатывает) ошибка вываливается при парсинге, выше ж писал


#11

ясно, я уже запутался в ответах
посмотрите в сторону ObjectMapper


#12
let json = """
{
    "response": {
        "count": 83,
        "items":[
            {
            "id": 7934694,
            },
            {
            "id": 7934696,
            }
        ]
    }
}
"""
struct Item: Decodable {
    let id:         Int
}

struct B: Decodable {
    
    private enum Keys: String, CodingKey { case response, count, items }
    
    let elements: [Item]
    
    init(from decoder: Decoder) throws {
        let containter = try (try decoder.container(keyedBy: Keys.self)).nestedContainer(keyedBy: Keys.self, forKey: .response)
        elements = try containter.decode([Item].self, forKey: .items)
    }
}


extension Array where Element == Item {

    private enum Keys: String, CodingKey { case response, count, items }
    
    init(from decoder: Decoder) throws {
        print("Arr")
        
        let containter = try (try decoder.container(keyedBy: Keys.self)).nestedContainer(keyedBy: Keys.self, forKey: .response)
        self = try containter.decode([Element].self, forKey: .items)
    }
    
}


let data = json.data(using: .utf8)!

let b = try! JSONDecoder().decode(B.self, from: data)
print(b, "\n\n")


let items = try! JSONDecoder().decode([Item].self, from: data)
print(items)

Если придумаете как можно override-нуть дефолтный инициализатор у Array для Codable вот вам решение) Я потыкал, не наше варианта чтобы он схватил мой init из extension