简体   繁体   中英

First TableView cells are not dequeuing properly

I'm working on the app, which loads flags to a class using https://www.countryflags.io/ API. I am loading a flag when initializing the object using Alamofire get request. The problem is that the first few TableView cells that are dequeued when starting the app are loaded without flags.

But when I scroll back after scrolling down, they load perfectly.

I thought that it is happening because the request is not processed quickly enough and the first flags are not ready to load before the start of dequeuing cells. But I have no idea how to setup something inside the getFlag() method to help me reload TableView data upon completion or delay dequeuing to the point when all flags are loaded.

Country class with getflag() method

import UIKit
import Alamofire

final class Country {
    let name: String
    let code: String
    var flag: UIImage?
    var info: String?

    init(name: String, code: String, flag: UIImage? = nil, info: String? = nil) {
        self.name = name
        self.code = code
        if flag == nil {
            getFlag()
        } else {
            self.flag = flag
        }
        self.info = info
    }

    func getFlag() {
        let countryFlagsURL = "https://www.countryflags.io/\(code.lowercased())/shiny/64.png"

        Alamofire.request(countryFlagsURL).responseData { response in
            if response.result.isSuccess {
                if let data = response.data {
                    self.flag = UIImage(data: data)
                }
            }
        }
    }
}

cellForRowAt method

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let country = countries[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "Country", for: indexPath)

        cell.textLabel?.text = country.name
        if let flag = country.flag {
            cell.imageView?.image = flag
        } else {
            cell.imageView?.image = .none
        }

        return cell
    }

The init method of Country should not be initiating the asynchronous image retrieval. Instead, you should have the cellForRowAt initiate the asynchronous image retrieval.

But you shouldn't just blithely update the cell asynchronously, either, (because the row may have been reused by the time your Alamofire request is done). And, a more subtle point, you'll want to avoid having image requests getting backlogged if you scroll quickly to the end of the tableview, so you want to cancel pending requests for rows that are no longer visible. There are a number of ways of accomplishing all three of these goals (async image retrieval in cellForRowAt , don't update cell after it has been used for another row, and don't let it get backlogged if scrolling quickly).

The easiest approach is to use AlamofireImage . Then all of this complexity of handling asynchronous image requests, canceling requests for reused cells, etc., is reduced to something like:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: “Country", for: indexPath)
    cell.imageView.af_setImage(withURL: objects[indexPath.row].url, placeholderImage: placeholder)
    return cell
}

Note, I'd suggest if you're going to use the default table view cell, that you supply a placeholder image in this routine, like shown above. Just create a blank image (or whatever) that is the same size as your flags. This ensures that the cell will be properly laid out.


By the way, if you'd like to generate that placeholder image programmatically, you can do something like:

let imageSize = CGSize(width: 44, height: 44)

lazy var placeholder: UIImage = UIGraphicsImageRenderer(size: imageSize).image { _ in
    UIColor.blue.setFill()
    UIBezierPath(rect: CGRect(origin: .zero, size: imageSize)).fill()
}

Now, that creates a blue placeholder thumbnail that is 44×44, but you can tweak colors and size as suits your application.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM