First of all, you need to use Autolayout to calculate the proper cell height by creating a proper set of constraints that would determine the cell height based on content. I am going to assume you did that.
Then you have to tell the tableView
you want it to use Autolayout to calculate height:
// my best estimation of the height
tableView.estimatedRowHeight = 144
// but the real height is calculated by autolayout
tableView.rowHeight = UITableViewAutomaticDimension
Now this would work if the autolayout could calculate the height correctly in cellForRowAt
. But since the image is downloaded asynchronously, the image is set later, when the cell may be already presented. This requires you to provide a way in which a cell can tell the tableView
that it has downloaded its content and its layout needs to be recalculated. To do so, use this method in the viewController
with the tableView
:
func recalculateTableViewLayout() {
self.tableView.beginUpdates()
self.tableView.setNeedsLayout()
self.tableView.endUpdates()
}
You will need to pass the reference to the viewController
with the tableView
to each cell (I recommend to use delegate pattern for that, here for brevity I will simply sketch it using it directly):
class FeedTableViewCell: UITableViewCell {
weak var feedViewController: FeedViewController?
// etc.
And in the cellForRowAt
:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeedTableViewCell", for: indexPath) as! FeedTableViewCell
cell.feedViewController = self
cell.configureCell(post: postArray[indexPath.row])
return cell
}
Then use completion handler of sd_setImage
to tell the tableView
to recalculate its layout when the image gets downloaded:
func configureCell(post: Post){
self.postImage.sd_setImage(with: URL(string: post.postImageURL), placeholderImage: UIImage(named: "default")) { (image, error, cache, url) in
self.feedViewController?.recalculateTableViewLayout()
}
}