0

How can I append into an array using JSON Model Class. Here is my JSON API Request: https://developer.github.com/v3/search/

import Foundation

typealias GitDecode = [GitDecodeElement]

struct GitDecodeElement: Codable {
    let totalCount: Int
    let incompleteResults: Bool
    let items: [Item]

    enum CodingKeys: String, CodingKey {
        case totalCount = "total_count"
        case incompleteResults = "incomplete_results"
        case items
    }
}

struct Item: Codable {
    let id: Int
    let nodeID, name, fullName: String
    let owner: Owner
    let itemPrivate: Bool
    let htmlURL, description: String
    let fork: Bool
    let url, createdAt, updatedAt, pushedAt: String
    let homepage: String
    let size, stargazersCount, watchersCount: Int
    let language: String
    let forksCount, openIssuesCount: Int
    let masterBranch, defaultBranch: String
    let score: Double

    enum CodingKeys: String, CodingKey {
        case id
        case nodeID = "node_id"
        case name
        case fullName = "full_name"
        case owner
        case itemPrivate = "private"
        case htmlURL = "html_url"
        case description, fork, url
        case createdAt = "created_at"
        case updatedAt = "updated_at"
        case pushedAt = "pushed_at"
        case homepage, size
        case stargazersCount = "stargazers_count"
        case watchersCount = "watchers_count"
        case language
        case forksCount = "forks_count"
        case openIssuesCount = "open_issues_count"
        case masterBranch = "master_branch"
        case defaultBranch = "default_branch"
        case score
    }
}

struct Owner: Codable {
    let login: String
    let id: Int
    let nodeID, avatarURL, gravatarID, url: String
    let receivedEventsURL, type: String

    enum CodingKeys: String, CodingKey {
        case login, id
        case nodeID = "node_id"
        case avatarURL = "avatar_url"
        case gravatarID = "gravatar_id"
        case url
        case receivedEventsURL = "received_events_url"
        case type
    }
}

And here I have my class Model where I'm saying what I want to extract from that response:

import Foundation

struct Git: Codable{

    let totalCount: Int
    let items: GitItem

    init ( totalCount: Int,
           itemID: Int, itemDescription: String,
          ownerID: Int, ownerAvatarURL: String) {

        self.totalCount = totalCount
        self.items = GitItem(id: itemID, description: itemDescription, owner: GitOwner(id: ownerID, avatarURL: ownerAvatarURL))
    }
}

struct GitItem: Codable{
    let id: Int
    let description: String
    let owner: GitOwner
}

struct GitOwner: Codable {
    let id: Int
    let avatarURL: String
}

Now I'm stuck when I try to append into my array all my custom properties because itemID, itemDescription, ownerID and ownerAvatarURL are in different classes.

Here is how I'm trying to get all the that properties from JSON using JSONDecoder:

import UIKit

class MainViewController: UIViewController {

    var gitRepositoriesArray = [Git]()

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    // Download Git Repositories from API
    func parseGitRepositories(){

        let url = URL(string: "https://developer.github.com/v3/search/")
        URLSession.shared.dataTask(with: url!) { (data, response, error) in
            if error == nil{
                do{
                    let gitRepositoriesList = try JSONDecoder().decode(GitDecode.self, from: data!)
                    for eachRepo in gitRepositoriesList{

                        self.gitRepositoriesArray.append(Git(totalCount: eachRepo.totalCount,
                                                    itemID: <#T##Int#> , itemDescription: <#T##String#>, ownerID: <#T##Int#>, ownerAvatarURL: <#T##String#>))


                    }

                }catch{
                    print(error.localizedDescription)
                }
            }
        }.resume()
    }
}
10
  • @matt I think they are just placeholders. Florentin.. I dont understand why there are two sets of models for the same thing? why dont you just decode the items into the model and use that instead of converting one model into another with less information? Commented Jun 9, 2018 at 16:25
  • That ones are placeholders. i67.tinypic.com/25kpla9.jpg Commented Jun 9, 2018 at 16:26
  • 1
    try for repo in gitRepositoriesList.items instead Commented Jun 9, 2018 at 16:28
  • I tried. Is not working. Commented Jun 9, 2018 at 16:31
  • how is it 'not working'? explain Commented Jun 9, 2018 at 16:32

2 Answers 2

2

Complete working playground code:

Makes a search against the API for Swift related repos.

Parses them, adds them to the array and prints out some basic information on each one. (fullName, name, avatarUrl

//: Playground - noun: a place where people can play
import PlaygroundSupport
import UIKit

struct GitDecodeElement: Codable {
    let totalCount: Int
    let incompleteResults: Bool
    let items: [Repo]

    enum CodingKeys: String, CodingKey {
        case totalCount = "total_count"
        case incompleteResults = "incomplete_results"
        case items
    }
}

struct Repo: Codable {
    let id: Int
    let nodeID, name, fullName: String
    let owner: Owner
    let itemPrivate: Bool
    let htmlURL, description: String
    let fork: Bool
    let url, createdAt, updatedAt, pushedAt: String
    let homepage: String?
    let size, stargazersCount, watchersCount: Int
    let language: String?
    let forksCount, openIssuesCount: Int
    let score: Double

    enum CodingKeys: String, CodingKey {
        case id
        case nodeID = "node_id"
        case name
        case fullName = "full_name"
        case owner
        case itemPrivate = "private"
        case htmlURL = "html_url"
        case description, fork, url
        case createdAt = "created_at"
        case updatedAt = "updated_at"
        case pushedAt = "pushed_at"
        case homepage, size
        case stargazersCount = "stargazers_count"
        case watchersCount = "watchers_count"
        case language
        case forksCount = "forks_count"
        case openIssuesCount = "open_issues_count"
        case score
    }
}

struct Owner: Codable {
    let login: String
    let id: Int
    let nodeID, avatarURL, gravatarID, url: String
    let receivedEventsURL, type: String

    enum CodingKeys: String, CodingKey {
        case login, id
        case nodeID = "node_id"
        case avatarURL = "avatar_url"
        case gravatarID = "gravatar_id"
        case url
        case receivedEventsURL = "received_events_url"
        case type
    }
}



var gitRepositoriesArray = [Repo]()

// Download Git Repositories from API
func parseGitRepositories() {

    let url = URL(string: "https://api.github.com/search/repositories?q=topic:swift+topic:ios")
    var request = URLRequest(url: url!)
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")

    URLSession.shared.dataTask(with: request) { (data, response, error) in

        guard error == nil else {
            print(error?.localizedDescription)
            return
        }

        do {
            let gitRepositoriesList = try JSONDecoder().decode(GitDecodeElement.self, from: data!)

            gitRepositoriesArray = gitRepositoriesArray + gitRepositoriesList.items
            print(gitRepositoriesArray.count)

            for repo in gitRepositoriesList.items {
                print("\(repo.fullName) - \(repo.name) - \(repo.owner.avatarURL)")
            }

        } catch {
            let str = String(data: data!, encoding: .utf8)
            print(str)
            print(error)
        }

    }.resume()
}

parseGitRepositories()

PlaygroundPage.current.needsIndefiniteExecution = true

Output:

30

justjavac/free-programming-books-zh_CN - free-programming-books-zh_CN - https://avatars1.githubusercontent.com/u/359395?v=4
dkhamsing/open-source-ios-apps - open-source-ios-apps - https://avatars0.githubusercontent.com/u/4723115?v=4
matteocrippa/awesome-swift - awesome-swift - https://avatars2.githubusercontent.com/u/475463?v=4
xitu/gold-miner - gold-miner - https://avatars2.githubusercontent.com/u/10482599?v=4
lkzhao/Hero - Hero - https://avatars1.githubusercontent.com/u/3359850?v=4
ReactiveX/RxSwift - RxSwift - https://avatars1.githubusercontent.com/u/6407041?v=4
realm/realm-cocoa - realm-cocoa - https://avatars0.githubusercontent.com/u/7575099?v=4
CocoaPods/CocoaPods - CocoaPods - https://avatars1.githubusercontent.com/u/1189714?v=4
CosmicMind/Material - Material - https://avatars1.githubusercontent.com/u/10069574?v=4
// rest truncated 

Notice how I use less models than you do in your code. There is no need to duplicate code, just use the parts you want, when you want them.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. Is finally working with so less modifications !
0

There is some problem in you Git structure. I have corrected the initializer like this:

struct Git: Codable{

let totalCount: Int
var items = [GitItem]()

init(totalCount: Int, items: [Item]) {
    self.totalCount = totalCount

    for item in items {
        self.items.append(GitItem(id: item.id, description: item.description, owner: GitOwner(id: item.owner.id, avatarURL: item.owner.avatarURL)))
    }

}

So your parsing method will be changed accordingly:

    // Download Git Repositories from API
func parseGitRepositories(){

    let url = URL(string: "https://api.github.com/search/repositories?q=tetris+language:assembly&sort=stars&order=desc")
    URLSession.shared.dataTask(with: url!) { (data, response, error) in
        if error == nil{
            do{
                let gitRepositoriesList = try JSONDecoder().decode(GitDecode.self, from: data!)
                for eachRepo in gitRepositoriesList{
                    self.gitRepositoriesArray.append(Git(totalCount: eachRepo.totalCount, items: eachRepo.items))
                }

            }catch{
                print(error.localizedDescription)
            }
        }
        }.resume()
}

Also note the change of url to https://api.github.com/search/repositories?q=tetris+language:assembly&sort=stars&order=desc. The current url that your are using in your code is just the html page with examples. It doesn't return proper json results.

2 Comments

I get an error when I try your example: "The data couldn’t be read because it isn’t in the correct format."
That is because you typealiased your GitDecode to be an array of GitDecodeElement but you are getting a dictionary in the response data instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.