Reputation: 4895
I have a UI widget as follows
class ProfileBubbleCell: UITableViewCell {
var roundImageView: UIImageView?
override func awakeFromNib() {
super.awakeFromNib()
self.contentView.backgroundColor = Color.red
initImage()
}
private func initImage(){
let imageView = UIImageView()
let width = self.frame.width
let height = self.frame.height
let img_width = height - 4
let img_height = img_width
let y = 2
let x = width/2 - img_width/2
imageView.frame = CGRect(
x: x, y: CGFloat(y), width: img_width, height: img_height
)
let rounded = imageView
.makeRounded()
.border(width:2.0, color:Color.white.cgColor)
// attach and save reference
self.addSubview(rounded)
self.roundImageView = rounded
}
private func loadImage(){
// @TODO: call parent function
}
}
And in loadImage
, I would like to call the parent's image loading view, and when the image is loaded, display it in roundImageView
. ProfileBubbleCell
is really meant to be as generic as possible, its only concern is making the image round and centering it.
This looks like a very common use case and I would like to delegate
the loading image task to the parent, but I am not sure how to express it.
In the parent I instantiate the cell as follows:
let cell = tableView.dequeueReusableCell(withIdentifier: "ProfileBubbleCell", for: indexPath) as! ProfileBubbleCell
Upvotes: 0
Views: 691
Reputation: 96
Here show you some about delegate use.
// 1) define delegate.
protocol ProfileBubbleCellDelegate {
func getImage() -> UIImage?
}
class ProfileBubbleCell: UITableViewCell {
// 2) declare a variable of ProfileBubbleCellDelegate
weak var delegate: ProfileBubbleCellDelegate?
//
func configure() {
self.roundImageView.image = delegate.getImage()
}
}
// when dequeueReuseCell on cellForRow(at:)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProfileBubbleCell", for: indexPath) as ProfileBubbleCell else { return UITableView() }
// 3) assign delegate to tableView's superView, maybe it's a UIViewController or UIView on your class.
cell.delegate = self
cell.configure()
return cell
}
// 4) extension Your class who be assigned delegate of ProfileBubbleCellDelegate
// and implement delegate's method.
extension YourClass: ProfileBubbleCellDelegate {
func getImage() -> UIImage? {
// 5) provide image.
return hereProvideYourImage
}
}
// or if you want immediately download image when cell.roundedImageView need it.
// modify the getImage() of Delegate like this.
protocol ProfileBubbleCellDelegate {
func getImage(completion: @escaping ((UIImage?) -> Void))
}
// then the extension implement will be
extension YourClass: ProfileBubbleCellDelegate {
func getImage(completion: @escaping ((UIImage?) -> Void)) {
downloadImageTask.downloadImage(url: imageUrl, completion: { downloadedImage in
// because completion will be passed on other closure of downloadImage(completion:),
// so delegate method need add `@escaping` that means the completion can escape from itself closure.
completion?(downloadedImage)
})
}
}
// don't forget replace called method on cell.
class ProfileBubbleCell: UITableViewCell {
// ...
func configure() {
delegate.getImage(completion: { downloadedImage in
DispatchQueue.main.async {
self.roundImageView.image = downloadedImage
}
})
}
}
Upvotes: 3