when i segue to a viewController with tableView, the tableviewcell immediately send a request to the server using the method fetchUserAvatar(avatarName: handler: (String) -> Void). and this method returns a url that link to the image. download it and cache the image cacheImage is an object of NSCache<NSString, UIImage>. this object cacheImage was initalised in previous view controller and being assigned from pervious to this viewContoller using prepare(for segue: UIStoryboardSegue, sender: Any?). when this viewController shows up, I can't see the image in the cell. but i pop the viewController out and segue to this viewController with tableView again. the image will show. I think(I guess) because
the images weren't all fully downloaded yet. so, i can't see the images. but if i pop out the viewController and load an object of viewController and the viewController gets the images from cache. therefore, the images could be shown.
I want to know how to avoid this problem? thanks.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell", for: indexPath) as! MessageCell
let row = indexPath.row
cell.content.text = messages[row].content
cell.date.text = messages[row].createdDateStrInLocal
cell.messageOwner.text = messages[row].user
if let avatar = cacheImage.object(forKey: messages[row].user as NSString){
cell.profileImageView.image = avatar
} else {
fetchUserAvatar(avatarName: messages[row].user, handler: { [unowned self] urlStr in
if let url = URL(string: urlStr), let data = try? Data(contentsOf: url), let avatar = UIImage(data: data){
self.cacheImage.setObject(avatar, forKey: self.messages[row].user as NSString)
cell.profileImageView.image = avatar
}
})
}
return cell
}
fileprivate func fetchUserAvatar(avatarName: String, handler: @escaping (String) -> Void){
guard !avatarName.isEmpty, let user = self.user, !user.isEmpty else { return }
let url = URL(string: self.url + "/userAvatarURL")
var request = URLRequest(url: url!)
let body = "username=" + user + "&avatarName=" + avatarName
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = body.data(using: .utf8)
defaultSession.dataTask(with: request as URLRequest){ data, response, error in
DispatchQueue.main.async {
if let httpResponse = response as? HTTPURLResponse {
if 200...299 ~= httpResponse.statusCode {
print("statusCode: \(httpResponse.statusCode)")
if let urlStr = String(data: data!, encoding: String.Encoding.utf8), urlStr != "NULL" {
handler(urlStr)
}
} else {
print("statusCode: \(httpResponse.statusCode)")
if let unwrappedData = String(data: data!, encoding: String.Encoding.utf8) {
print("POST: \(unwrappedData)")
self.warning(title: "Fail", message: unwrappedData, buttonTitle: "OK", style: .default)
} else {
self.warning(title: "Fail", message: "unknown error.", buttonTitle: "OK", style: .default)
}
}
} else if let error = error {
print("Error: \(error)")
}
}
}.resume()
}
I modified it, and move the download code in viewdidload and reload the tableview, the result is the same.