Объекты, содержащие фотографии, взятые с сервера, должны перезагрузить tableView, содержащий объекты - PullRequest
0 голосов
/ 29 ноября 2018

У меня есть tableView в ViewController, содержащий массив объектов Channel;массив заполняется из строки json, сохраненной в моей базе данных CoreData

парсинг json и создание объектов Channel У меня может быть типичная переменная, такая как id, имя канала и члены разговора;это объект 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)
            }
        }
    }
}

Переменная profileImage должна быть взята с Сервера с API, проблема в том, что когда объект был создан при разборе json в функции getDataFromCoreData() the Channelобъекты в массиве имеют переменную id, name и members, но по-прежнему не имеют изображений, поэтому в моем tableView будут строки для различных каналов, но без profileImage из-за асинхронного вызова.

InВ моем случае перезагрузить таблицу для визуализации изображений сделал функцию loadImages() для ожидания завершения асинхронного вызова и перезагрузить 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
    }
}

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

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Существует множество библиотек, расширяющих UIImageView для решения этой проблемы:

AlamofireImage Nuke SDWebImage KingFisher

Архитектурно, где они отличаются от вашего решения: 1) Существует отдельный кэш изображений, сохраненный на диск (иногда NSCache, иногда нет), который предотвращает повторную загрузку одного и того же изображения, но также избавляет вас от необходимости хранить всев базе данных (вы просто храните URL).2) Расширение находится в UIImageView, поэтому представления изображений знают, как загрузить URL-адрес и отменить запрос, если представление изображений разрушается до его завершения.Как правило, они предлагают дополнительные функции, такие как изображение-заполнитель для использования во время загрузки, изменение размера изображений и т. Д. Не так сложно написать собственный кэш, хотя я почти всегда просто использую один из модулей.Вот очень простой кеш, который я написал для демонстрационного проекта, в котором я не хотел использовать модуль:

class ImageCache {
    enum Result {
        case success(UIImage, URL), failure (Error)
    }
    static let shared = ImageCache()
    private let cache = NSCache<NSURL, UIImage>()
    private init() { }
    func image(for url: URL, completion: @escaping (Result) -> ()) {
        guard let image = cache.object(forKey: url as NSURL) else {
            DispatchQueue.global(qos: .userInitiated).async { [weak self] in
                guard let `self` = self,
                      let image = UIImage.gif(url: url.absoluteString) else {
                    completion(.failure(NSError()))
                    return
                }
                self.cache.setObject(image, forKey: url as NSURL)
                completion(.success(image, url))
            }
            return
        }
        completion(.success(image, url))
    }
}
0 голосов
/ 29 ноября 2018

Может быть, вы могли бы каждый раз перезагружать одну ячейку вместо всего UITableView:

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

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

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

РЕДАКТИРОВАТЬ: вы можете проверить в CellForRowAtIndexPath, если изображение равно нулю, а затем загрузить его изваш сервер.При успешном закрытии перезагрузите саму ячейку ... у вас уже есть indexPath.используйте слабое Я, чтобы избежать сохраняющихся циклов.

...