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([])
}
}