UIKit delegates and protocols
Sofia Martinez
Jan 2026
1 tab
import UIKit
// MARK: - Custom Delegate Protocol
protocol PostCellDelegate: AnyObject {
func postCell(_ cell: PostTableViewCell, didTapLike post: Post)
func postCell(_ cell: PostTableViewCell, didTapComment post: Post)
func postCell(_ cell: PostTableViewCell, didTapShare post: Post)
}
class PostTableViewCell: UITableViewCell {
weak var delegate: PostCellDelegate?
private var post: Post?
private let likeButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(systemName: "heart"), for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private let commentButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(systemName: "bubble.left"), for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
contentView.addSubview(likeButton)
contentView.addSubview(commentButton)
likeButton.addTarget(self, action: #selector(likeTapped), for: .touchUpInside)
commentButton.addTarget(self, action: #selector(commentTapped), for: .touchUpInside)
NSLayoutConstraint.activate([
likeButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -12),
likeButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
commentButton.centerYAnchor.constraint(equalTo: likeButton.centerYAnchor),
commentButton.leadingAnchor.constraint(equalTo: likeButton.trailingAnchor, constant: 20)
])
}
func configure(with post: Post) {
self.post = post
}
@objc private func likeTapped() {
guard let post = post else { return }
delegate?.postCell(self, didTapLike: post)
}
@objc private func commentTapped() {
guard let post = post else { return }
delegate?.postCell(self, didTapComment: post)
}
}
// MARK: - View Controller Implementing Delegate
class FeedViewController: UIViewController {
private let tableView = UITableView()
private var posts: [Post] = []
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
}
private func setupTableView() {
tableView.delegate = self
tableView.dataSource = self
tableView.register(PostTableViewCell.self, forCellReuseIdentifier: "PostCell")
}
}
extension FeedViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! PostTableViewCell
cell.configure(with: posts[indexPath.row])
cell.delegate = self
return cell
}
}
extension FeedViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let post = posts[indexPath.row]
// Navigate to detail
}
}
extension FeedViewController: PostCellDelegate {
func postCell(_ cell: PostTableViewCell, didTapLike post: Post) {
print("Like tapped for post \(post.id)")
// Handle like action
}
func postCell(_ cell: PostTableViewCell, didTapComment post: Post) {
print("Comment tapped for post \(post.id)")
// Navigate to comments
}
func postCell(_ cell: PostTableViewCell, didTapShare post: Post) {
print("Share tapped for post \(post.id)")
// Show share sheet
}
}
// MARK: - Protocol with Associated Type
protocol DataProvider {
associatedtype Item
func fetchItems(completion: @escaping ([Item]) -> Void)
}
class PostsDataProvider: DataProvider {
typealias Item = Post
func fetchItems(completion: @escaping ([Post]) -> Void) {
// Fetch posts from API
completion([])
}
}
1 file · swift
Explain with highlit
Delegates enable objects to communicate events and customize behavior. The delegate pattern uses protocols to define a contract—I create a protocol with optional and required methods, and the delegating object holds a weak reference to avoid retain cycles. Common system delegates include UITableViewDelegate, UITextFieldDelegate, and UICollectionViewDelegate. For custom delegates, I define protocols for specific responsibilities like network callbacks or view controller events. The weak keyword prevents retain cycles when parent objects delegate to children. Protocols can have associated types with associatedtype for generic constraints. This pattern promotes loose coupling and testability through dependency injection.