Search code examples
iosswiftuitableviewnsobject

Objects contain photo taken from server should reload tableView containing the objects


I have a tableView in a ViewController containing an array of objects Channel; the array is populated from a json string saved in my CoreData Database

Parsing the json and creating the objects Channel I can have typical variable like id, the name of the channel and the members of the conversation; this is the object Channel

class Channel: NSObject {
    var id: String?
    var name: String?
    var members = [Member]()

    var profileImage: UIImage?

    override init() {
       super.init()
    }

    init(id: String, name: String, members: [String]) {
        super.init()
        self.id = id
        self.name = name
        for idMember in members {
            let newMember = Member(id: idMember)
            self.members.append(newMember)
        }
    }

    func loadPhoto(id: Int, completion: @escaping (Bool) -> Void) {
        Helper.getImage(id: id) { (imageResult) in
            if let image = imageResult {
                self.profileImage = image
                completion(true)
            } else {
                completion(false)
            }
        }
    }
}

The variable profileImage should be taken from a Server with an API, the problem is that when the object has been created parsing the json in the function getDataFromCoreData() the Channel objects in the array have the variable id, name and members but still don't have the images, so my tableView will have the rows for the various channels but without the profileImage, because of the async call.

In my case to reload the table to visualize the images a made a function loadImages() to wait for async call to finish and reload the tableView

import UIKit
import Firebase

class ConversationsViewController: UIViewController {

    var channelList = [Channel]()

    override func viewDidLoad() {
        super.viewDidLoad()
        //I get the channelList from a JSON saved like a string in my coreData with a custom function
        channelList = getDataFromCoreData()
        loadImages()
    }

    func loadImages() {
        for channel in self.channelList {
            channel.loadPhoto(id: channel.id) { success in
                if success {
                    self.chatTable.reloadData()
                }
            }
        }
    }
}
extension ConversationsViewController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MessageChannelTableViewCell

        var channel = channelList[indexPath.row]

        cell.titleLabel.text = channel.name

        if let profileImage = channel.profileImage {
            cell.profileImage.image = profileImage
        } else {
            if channel.members.count > 2 {
                cell.profileImage.image = theme.groupChatImage
            } else {
                cell.profileImage.image = UIImage(named: "profile-icon")!
            }
        }

        return cell
    }

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

I know that the question can be long and boring, but i want to know if there is a better way to do it, and if yes you can tell me to improve my code


Solution

  • Maybe you could reload a single cell instead of the whole UITableView every time:

    You should find a way to get the indexPathRow of every cell that needs to download the image and then:

    let indexPosition = IndexPath(row: indexPathRow, section: 0)
    tableView.reloadRows(at: [indexPosition], with: .none)
    

    ...take a look at the enum options for the animation to choose the one that fits your app.

    EDIT: you could test in the CellForRowAtIndexPath if the image is nil and then load it from your server. In the success closure reload the cell itself... you alredy have the indexPath. use weak self to avoid retained cycles.