swift
197 lines · 2 tabs
Sofia Martinez
Jan 2026
2 tabs
import UIKit
import Combine
class PostsTableViewController: UITableViewController {
enum Section {
case main
}
struct PostItem: Hashable {
let id: Int
let title: String
let body: String
let author: String
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
private var dataSource: UITableViewDiffableDataSource<Section, PostItem>!
private let viewModel = PostsViewModel()
private var cancellables = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
title = "Posts"
setupTableView()
configureDataSource()
bindViewModel()
viewModel.loadPosts()
}
private func setupTableView() {
tableView.register(
PostTableViewCell.self,
forCellReuseIdentifier: "PostCell"
)
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 100
refreshControl = UIRefreshControl()
refreshControl?.addTarget(
self,
action: #selector(handleRefresh),
for: .valueChanged
)
}
private func configureDataSource() {
dataSource = UITableViewDiffableDataSource<Section, PostItem>(
tableView: tableView
) { tableView, indexPath, item in
let cell = tableView.dequeueReusableCell(
withIdentifier: "PostCell",
for: indexPath
) as! PostTableViewCell
cell.configure(with: item)
return cell
}
}
private func bindViewModel() {
viewModel.$posts
.receive(on: DispatchQueue.main)
.sink { [weak self] posts in
self?.updateSnapshot(with: posts)
}
.store(in: &cancellables)
viewModel.$isLoading
.receive(on: DispatchQueue.main)
.sink { [weak self] isLoading in
if !isLoading {
self?.refreshControl?.endRefreshing()
}
}
.store(in: &cancellables)
}
private func updateSnapshot(with posts: [Post], animated: Bool = true) {
var snapshot = NSDiffableDataSourceSnapshot<Section, PostItem>()
snapshot.appendSections([.main])
let items = posts.map { post in
PostItem(
id: post.id,
title: post.title,
body: post.body,
author: post.author.name
)
}
snapshot.appendItems(items, toSection: .main)
dataSource.apply(snapshot, animatingDifferences: animated)
}
@objc private func handleRefresh() {
viewModel.loadPosts()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
guard let item = dataSource.itemIdentifier(for: indexPath) else { return }
// Navigate to detail
let detailVC = PostDetailViewController(postId: item.id)
navigationController?.pushViewController(detailVC, animated: true)
}
override func tableView(
_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(
style: .destructive,
title: "Delete"
) { [weak self] _, _, completion in
guard let item = self?.dataSource.itemIdentifier(for: indexPath) else {
completion(false)
return
}
self?.viewModel.deletePost(id: item.id)
completion(true)
}
return UISwipeActionsConfiguration(actions: [deleteAction])
}
}
import UIKit
class PostTableViewCell: UITableViewCell {
private let titleLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 18, weight: .semibold)
label.numberOfLines = 2
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let bodyLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 14)
label.textColor = .secondaryLabel
label.numberOfLines = 3
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let authorLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 12)
label.textColor = .tertiaryLabel
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
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(titleLabel)
contentView.addSubview(bodyLabel)
contentView.addSubview(authorLabel)
NSLayoutConstraint.activate([
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12),
titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
bodyLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8),
bodyLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
bodyLabel.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor),
authorLabel.topAnchor.constraint(equalTo: bodyLabel.bottomAnchor, constant: 8),
authorLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
authorLabel.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor),
authorLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -12)
])
}
func configure(with item: PostsTableViewController.PostItem) {
titleLabel.text = item.title
bodyLabel.text = item.body
authorLabel.text = "By \(item.author)"
}
}
2 files · swift
Explain with highlit
Diffable data sources modernize UITableView and UICollectionView, automatically calculating and animating changes. Instead of manually calling insert/delete methods, I create snapshots with current state and apply them. The framework diffs snapshots and animates transitions. This eliminates index path bugs and makes updates declarative. I define sections and items with Hashable types, create a UITableViewDiffableDataSource, and configure cells in closure. When data changes, I build a new snapshot and apply it—animations happen automatically. Diffable data sources work with both UIKit and SwiftUI's UIViewRepresentable, bridging modern APIs to legacy codebases.
Related snips
swift
import Combine
import Foundation
class SearchViewModel: ObservableObject {
@Published var searchQuery = ""
@Published var results: [SearchResult] = []
Combine operators for data transformation
swift
combine
reactive
by Sofia Martinez
1 tab
swift
import SwiftUI
struct ContentView: View {
@State private var username = ""
@State private var isLoggedIn = false
@StateObject private var viewModel = LoginViewModel()
SwiftUI declarative UI with state management
swift
swiftui
ios
by Sofia Martinez
2 tabs
swift
import SwiftUI
struct CardModifier: ViewModifier {
var backgroundColor: Color = .white
var cornerRadius: CGFloat = 12
var shadowRadius: CGFloat = 5
Custom SwiftUI view modifiers for reusability
swift
swiftui
ios
by Sofia Martinez
2 tabs
swift
import Foundation
import UIKit
class ImageProcessor {
// Background processing with main thread updates
func processImage(_ image: UIImage, completion: @escaping (UIImage?) -> Void) {
Grand Central Dispatch for concurrency
swift
gcd
concurrency
by Sofia Martinez
1 tab
swift
import SwiftUI
enum Route: Hashable {
case postDetail(id: Int)
case userProfile(id: Int)
case settings
Navigation patterns with NavigationStack
swift
swiftui
navigation
by Sofia Martinez
2 tabs
swift
import UIKit
import WebKit
class WebViewController: UIViewController {
private var webView: WKWebView!
private var progressView: UIProgressView!
WKWebView for web content display
swift
wkwebview
webkit
by Sofia Martinez
1 tab
Share this code
Here's the card — post it anywhere.