将图像异步加载到自定义 UITableViewCell 部分工作

Posted

技术标签:

【中文标题】将图像异步加载到自定义 UITableViewCell 部分工作【英文标题】:Async load image to custom UITableViewCell partially working 【发布时间】:2017-04-28 12:47:39 【问题描述】:

我的图像不会加载到图像视图中,直到您将单元格从表格中滚动并重新打开,或者转到另一个视图并返回视图(重绘单元格)。

如何让它们正确加载?

/////////

我的 viewDidLoad 里面有这个:

    tableView.delegate = self
    tableView.dataSource = self

    DispatchQueue.global(qos: .background).async 
        self.getBusinesses()

        DispatchQueue.main.async 

            self.tableView.reloadData()


        
    

我在viewDidLoad中调用的.getBusinesses函数中调用了下载图片的函数:

func getBusinesses() -> Array<Business> 

    var businessList = Array<Business>()
    //let id  = 1
    let url = URL(string: "**example**")!
    let data = try? Data(contentsOf: url as URL)
    var isnil = false

    if data == nil
        isnil = true
    
    print("is nill is \(isnil)")


    if(data == nil)
        print("network error")
        businessList = []
        return businessList
    
    else
        values = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
    

    let json = JSON(values)

    var i = 0;
    for (key, values) in json 

        var businessReceived = json[key]
        let newBusiness = Business(id: "18", forename: "", surname: "", email: "", password: "", business: true, level: 1, messageGroups: [], problems: [])

        newBusiness.name = businessReceived["name"].stringValue
        newBusiness.description = businessReceived["description"].stringValue
        newBusiness.rating = Int(businessReceived["rating"].doubleValue)
        newBusiness.category = businessReceived["category"].intValue
        newBusiness.distance =  Double(arc4random_uniform(198) + 1)
        newBusiness.image_url  = businessReceived["image"].stringValue
        newBusiness.url  = businessReceived["url"].stringValue
        newBusiness.phone  = businessReceived["phone"].stringValue
        newBusiness.postcode  = businessReceived["postcode"].stringValue
        newBusiness.email = businessReceived["email"].stringValue
        newBusiness.id = businessReceived["user_id"].stringValue

        if(newBusiness.image_url  == "")
            newBusiness.getImage()

        
        else
            newBusiness.image = #imageLiteral(resourceName: "NoImage")
        


        if(businessReceived["report"].intValue !=  1)
            businessList.append(newBusiness)

        
    

    businesses = businessList

    print(businesses.count)
    holdBusinesses = businessList
    return businessList


在业务对象中,我有这种方法可以从 url 下载图像并将其存储在业务对象的图像属性中:

 func getImage()

    if(self.image_url != "")

        print("runs imageeee")
        var storage = FIRStorage.storage()

        // This is equivalent to creating the full reference
        let storagePath = "http://firebasestorage.googleapis.com\(self.image_url)"
        var storageRef = storage.reference(forURL: storagePath)




        // Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
        storageRef.data(withMaxSize: 30 * 1024 * 1024)  data, error in
            if let error = error 
                // Uh-oh, an error occurred!
             else 
                // Data for "images/island.jpg" is returned
                self.image = UIImage(data: data!)!
                print("returned image")
            
        


    
    else

        self.image = #imageLiteral(resourceName: "NoImage")

    


然后我在这里的tableview中输出:

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

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


            cell.businessImage.image = businesses[(indexPath as NSIndexPath).row].image


            //.............  

     return cell

【问题讨论】:

用SDwebImage就好了 但如果您记得下载是异步的,则更相关 - 因此当您在 viewDidLoad 中调用 tableView.reloadData() 时没有可用数据 - 查看委托调用,并使用它们来触发视图仅在数据可用时重新加载 tableView 听起来很有趣,如果它在下载图像时加载了 tableview 那就完美了!你有这方面的经验吗@Russell 您在哪里使用返回的图像填充数组业务[]? downloadImage() 似乎只是设置了一个值。另外 - 如果你在同一个类中做所有事情,它甚至比使用委托更简单 - 只需确保从下载的完成处理程序中刷新 tableView 在 viewdidload 中调用的 getBusinesses 函数中,现在将修改原始代码供您查看@Russell 【参考方案1】:
            self.image = UIImage(data: data!)!

应该变成

    DispatchQueue.main.async 
         self.image = UIImage(data: data!)!
    

里面

    storageRef.data(withMaxSize: 30 * 1024 * 1024)  data, error in

编辑:我最初的想法是下载逻辑在单元格内,现在我知道它不是。

每次到达时都需要在 tableView 上调用 reloadData()

         self.image = UIImage(data: data!)!

或者更好的是找出你刚刚更新的索引,然后调用

  tableView.reloadRows:[IndexPath]

【讨论】:

您如何建议将这些方法中的任何一种作为 self.image = UIImage(data: data!)!是在对象中的一个方法中,所以无法从那里重新加载数据,而且因为第二种方式,tableview 是从我拥有所有数据时开始加载的? @SeanLintern88 道歉应该说 getImage(),复制了错误的函数,但是除了名称之外它们完全一样,所以在这里更改了我的代码。正如您现在看到的,您知道正确的名称,它在 getBusinesses() 中被调用,抱歉! @SeanLintern88 我会将 getImage 移动到单元格中......然后给单元格指定路径,然后下载它。 对不起@SeanLintern88 我没有完全理解你的意思 将getImage()函数放入单元格中,然后在配置单元格的路径时,获取图像【参考方案2】:

你可以使用

cell.businessImage.setNeedsLayout()

【讨论】:

以上是关于将图像异步加载到自定义 UITableViewCell 部分工作的主要内容,如果未能解决你的问题,请参考以下文章

如何将图像保存到自定义相册?

Phonegap(cordova)将图像保存到自定义相册

如何将图像保存到自定义相册?

IOS:将图像添加到自定义 MKAnnotationview

将图像添加到自定义复选框

如何将 FBSDKLoginButton 默认图像添加到自定义 UIButton?