【问题标题】:How to update data model using DispatchQueue.main.async/Block/Closures in Swift 3如何在 Swift 3 中使用 DispatchQueue.main.async/Block/Closures 更新数据模型
【发布时间】:2023-03-30 07:14:01
【问题描述】:

我正在学习 Swift。我有一个问题。

问题- 我有带有图片 url 的 DataModel,所以第一次会从 url 下载图片,当然第二次不会。因此,当我在我的块中获取图像时,我想用图像更新我的数据模型。但它不起作用。

  • 我尝试过使用 inout 函数
  • 还有completionHander 回调

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*
            }
        }
    }
}

【问题讨论】:

  • OffersModelstruct 吗?
  • 这是一种危险的方式,因为如果用户滚动并且单元格离开屏幕,您将获得不可预知的行为。请看LazyTableImages
  • 是的@Sulthan,它是结构。现在我已经在 Class 和它的工作上改变了它。现在我删除了 completionHandler 回调并在它完成后直接更新。顺便说一句,如果我们使用 completionHandler,我们必须避免转义,这在 Swift 3 中是默认设置的……对吗?

标签: swift swift3 closures capture-list


【解决方案1】:

来自 cmets modelstruct

struct(或任何值类型)传递给方法或将其分配给变量时,struct 被复制。

因此,model.image = image 实际上是将image 分配给一个全新的model,而不是原来的model

使用引用类型(class)将修复它。

【讨论】:

    【解决方案2】:

    以下是基于您的代码的潜在解决方案,但是,正如 vadain 在 cmets 中所说,这有点危险,因为图像加载是异步的,并且可能在单元格不再存在时返回图像。

    理想情况下,您要做的是将模型设置为持久性,并且它应该发送异步请求以下载其图像。然后,当图像返回时,它会更新模型,并且模型会广播一条消息,说明它的图像已更新。细胞可以在模型存在时侦听并响应模型的更新。

    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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-31
      • 1970-01-01
      • 2018-01-11
      • 1970-01-01
      • 2020-04-19
      • 2015-09-11
      • 1970-01-01
      相关资源
      最近更新 更多