Как обновить модель данных с помощью DispatchQueue.main.async/Block/Closures в Swift 3

Я учу Свифта. У меня есть одна проблема.

Проблема- у меня есть DataModel с URL-адресом изображения, поэтому первый раз загрузит изображение с URL-адреса и, конечно, второй раз не будет. Поэтому, когда я получаю изображение в своем блоке, я хочу обновить свою модель данных изображением. Но это не работает.

  • Я пробовал с функцией inout
  • Также завершение перезвонить

ViewController.swift

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "OffersTableCell", for: indexPath) as! OffersTableCell

    var model = offersArray[indexPath.row] as! OffersModel
    cell.updateOfferCellWith(model: model, completionHandler: { image in
        model.image = image
    })///// I am getting image here, but model is not getting update
    return cell
}

Cell.Swift

func updateOfferCellWith(model: OffersModel, completionHandler:@escaping (UIImage) -> Void) {

    if (model.image != nil) { //Second time this block should be execute, but model image is always nil
        DispatchQueue.main.async { [weak self] in
            self?.offerImageView.image = model.image
        }
    }
    else{
        //First time- Download image from URL
        ImageDownloader.downloadImage(imageUrl: model.offerImageURL) { [weak self] image in
            DispatchQueue.main.async {[model] in
                var model = model
                self?.offerImageView.image = image
                //model.image = image*//This is also not working*
                completionHandler(image)*//Call back*
            }
        }
    }
}

2 ответа

Решение

Из комментариев model это struct,

При прохождении struct (или любой тип значения) для метода или присвоения его переменной, struct копируется.

Следовательно model.image = image на самом деле присваивает image совершенно новый model а не к оригиналу model,

Использование ссылочного типа (class) это исправит.

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

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

func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "OffersTableCell", for: indexPath) as! OffersTableCell

    var model = offersArray[indexPath.row] as! OffersModel

    if image = model.image {
        // setting directly here... you could call an image on the cell if you want more data encapuslation
        cell.offerImageView.image = model.image
    } else {
        ImageDownloader.downloadImage(imageUrl: model.offerImageURL) { [weak self] image in
            DispatchQueue.main.async {
                model.image = image
                cell.offerImageView.image = image
            }
        }
    }

    return cell
}
Другие вопросы по тегам