1

I've got 2 JSON from different API.

This one (Activities):

{
    "oldest": "2019-01-24T00:00:00+00:00",
    "activities": [
        {
            "message": "<strong>Henrik</strong> didn't resist a guilty pleasure at <strong>Starbucks</strong>.",
            "amount": 2.5,
            "userId": 2,
            "timestamp": "2019-05-23T00:00:00+00:00"
        },
        {
            "message": "<strong>You</strong> made a manual transfer.",
            "amount": 10,
            "userId": 1,
            "timestamp": "2019-01-24T00:00:00+00:00"
        }
    ]
}

And this one (Users):

[
    {
        "userId": 1,
        "displayName": "Mikael",
        "avatarUrl": "http://qapital-ios-testtask.herokuapp.com/avatars/mikael.jpg"
    },
    {
        "userId": 6,
        "displayName": "Daniel",
        "avatarUrl": "http://qapital-ios-testtask.herokuapp.com/avatars/daniel.jpg"
    }
]

There a lot more activities and users inside but I removed them to make this shorter.

Now, the goal would be to have something like this: example.

I've set up a MainViewController and a MainViewControllerCell

MainViewController:

struct Activities: Decodable {
    let oldest: String
    let activities: [Activity]
}

struct Activity: Decodable {
    let message: String
    let amount: Float
    let userId: Int
    let timestamp: String
}

struct Users: Decodable {
    let avatarUrl: String
    let displayName: String
    let userId: Int
}

class MainTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

//        let userJSONURLString = "https://qapital-ios-testtask.herokuapp.com/users"
        let activitiesJSONURLString = "https://qapital-ios-testtask.herokuapp.com/activities?from=2016-05-23T00:00:00+00:00&to=2019-05-23T00:00:00+00:00"
//        guard let userURL = URL(string: userJSONURLString) else { return }
        guard let activitiesURL = URL(string: activitiesJSONURLString) else { return }

        URLSession.shared.dataTask(with: activitiesURL) { (data, response, err) in

            guard let data = data else { return }

            do {
                // Activities
                let activities = try JSONDecoder().decode(Activities.self, from: data)
                print(activities)

                // Users
//                let users = try JSONDecoder().decode([Users].self, from: data)
//                print(users)

            } catch let jsonErr {
                print("Error serializing json: ", jsonErr)
            }

        }.resume()
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 0
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 0
    }

MainControllerViewCell

class MainTableViewCell: UITableViewCell {

    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var dateLabel: UILabel!
    @IBOutlet weak var amountLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

As you can see, I can already read the JSON. Now, I've never done this before so I don't know which is the best approach.

How would I connect the userId from Activity to the userId from Users?

How would I connect the amount, message, and the avatars to the labels?

Basically how do I populate the cells with the JSONs to have it like the example?

luwec
  • 35
  • 6
  • 1
    Make `activities` a property in your VC, and return the count in `numberOfRowsInSection`. Then implement `cellforrowatindexpath` and populate each cell. You can find a gazillion examples online how to do that. For instance: https://stackoverflow.com/questions/33234180/uitableview-example-for-swift – koen Jun 07 '19 at 01:55
  • Hey! Thanks for responding. Like this? `var activities: [Activities] = []` – luwec Jun 07 '19 at 23:26
  • In that case, you need to access `activities.activities` to get the count and data for each cell. But do you really need `oldest`? Otherwise you could skip the `Activities` struct, and store your data in an array of `Activity` structs. Each will have the timestamp anyway, so you can always extract `oldest` from your `activities` array. – koen Jun 08 '19 at 18:48

1 Answers1

0

You can achieve this that way:

in your MainControllerViewCell add a property for User

class MainTableViewCell: UITableViewCell {

    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var dateLabel: UILabel!
    @IBOutlet weak var amountLabel: UILabel!

    var user: User? {
        didSet {
            descriptionLabel.text = user?.displayName 
            // etc... you set your cell's outlets in accordance to `user`s infos
        }
    }
}

then in your MainTableViewController you register the decoded users and reload the tableView

class MainTableViewController: UITableViewController {

    var userList: [User] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        let activitiesJSONURLString = "https://qapital-ios-testtask.herokuapp.com/activities?from=2016-05-23T00:00:00+00:00&to=2019-05-23T00:00:00+00:00"
        guard let activitiesURL = URL(string: activitiesJSONURLString) else { return }

        URLSession.shared.dataTask(with: activitiesURL) { (data, response, err) in

            guard let data = data else { return }

            do {
                // Activities
                let activities = try JSONDecoder().decode(Activities.self, from: data)
                print(activities)

                // Users
                let users = try JSONDecoder().decode([Users].self, from: data)
                userList = [] 
                userList.append(users)
                tableView.reloadData // reload 

            } catch let jsonErr {
                print("Error serializing json: ", jsonErr)
            }

        }.resume()
    }

    // MARK: - Table view data source

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return userList.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        cell = dequeueReusableCell(withIdentifier: "MyCellIdentifier", for: indexPath) as! MainTableViewCell
        cell.user = userList[indexPath.row]
        return cell
    }
}

you bind your userList to the TableView datasource, and you reload datas every time the URLSession is finished and the decoder worked

Olympiloutre
  • 2,268
  • 3
  • 28
  • 38
  • Hey! Thank you for your response. I've got some questions: 1) You added a property for `User`, do you mean `Users`? 2) Wouldn't I need also an `Activity` property? 3) `userList.append(users)` throws `Cannot convert value of type '[Users]' to expected argument type 'Users'` – luwec Jun 07 '19 at 23:24
  • 1) yes I mean Users. 2) of course anything that you want to be displayed in your cell. This is a showcase you have to adapt it to your needs. 3) there is a way to append two lists. You could even try userList = users, it ay work – Olympiloutre Jun 08 '19 at 05:16