swift
141 lines · 2 tabs
Sofia Martinez
Jan 2026
2 tabs
import SwiftUI
struct PostsListView: View {
@StateObject private var viewModel = PostsListViewModel()
var body: some View {
NavigationView {
List {
ForEach(viewModel.posts) { post in
NavigationLink {
PostDetailView(postId: post.id)
} label: {
PostRowView(post: post)
.onAppear {
if post.id == viewModel.posts.last?.id {
viewModel.loadMoreIfNeeded()
}
}
}
}
if viewModel.isLoadingMore {
HStack {
Spacer()
ProgressView()
Spacer()
}
}
}
.listStyle(.plain)
.navigationTitle("Posts")
.refreshable {
await viewModel.refresh()
}
.overlay {
if viewModel.isLoading && viewModel.posts.isEmpty {
ProgressView()
} else if viewModel.posts.isEmpty {
ContentUnavailableView(
"No Posts",
systemImage: "doc.text",
description: Text("No posts available")
)
}
}
.alert("Error", isPresented: $viewModel.showError) {
Button("OK") { }
} message: {
Text(viewModel.errorMessage ?? "Unknown error")
}
}
.task {
await viewModel.loadInitialPosts()
}
}
}
struct PostRowView: View {
let post: Post
var body: some View {
VStack(alignment: .leading, spacing: 8) {
Text(post.title)
.font(.headline)
Text(post.body)
.font(.subheadline)
.foregroundColor(.secondary)
.lineLimit(2)
HStack {
Label("\(post.likesCount)", systemImage: "heart")
Label("\(post.commentsCount)", systemImage: "bubble.left")
Spacer()
Text(post.createdAt, style: .relative)
}
.font(.caption)
.foregroundColor(.secondary)
}
.padding(.vertical, 4)
}
}
import Foundation
import Combine
@MainActor
class PostsListViewModel: ObservableObject {
@Published var posts: [Post] = []
@Published var isLoading = false
@Published var isLoadingMore = false
@Published var errorMessage: String?
@Published var showError = false
private var currentPage = 1
private var hasMore = true
private let apiService = APIService.shared
func loadInitialPosts() async {
guard !isLoading else { return }
isLoading = true
errorMessage = nil
currentPage = 1
do {
let newPosts = try await apiService.fetchPosts(page: currentPage)
posts = newPosts
hasMore = newPosts.count >= 20 // Assuming 20 per page
} catch {
errorMessage = error.localizedDescription
showError = true
}
isLoading = false
}
func refresh() async {
await loadInitialPosts()
}
func loadMoreIfNeeded() {
guard !isLoadingMore && hasMore else { return }
Task {
isLoadingMore = true
currentPage += 1
do {
let newPosts = try await apiService.fetchPosts(page: currentPage)
posts.append(contentsOf: newPosts)
hasMore = newPosts.count >= 20
} catch {
errorMessage = error.localizedDescription
showError = true
currentPage -= 1 // Rollback on error
}
isLoadingMore = false
}
}
}
2 files · swift
Explain with highlit
Lists are fundamental to iOS apps, displaying scrollable collections efficiently. SwiftUI's List or ScrollView with LazyVStack renders items on-demand. I add pull-to-refresh with the .refreshable modifier, calling async refresh logic. For infinite scroll, I detect when the last item appears using onAppear and trigger pagination. The ViewModel tracks current page and hasMore state. Pagination prevents duplicate loads with loading flags. For performance with large datasets, I use LazyVStack instead of VStack to avoid rendering off-screen views. This pattern provides smooth, responsive lists that scale to thousands of items.
Related snips
ruby
class PostsController < ApplicationController
def index
@posts = Post.includes(:author)
.order(created_at: :desc)
.page(params[:page])
.per(10)
Turbo Frames: infinite scroll with lazy-loading frame
rails
turbo
hotwire
by codesnips
4 tabs
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
ruby
module Paginatable
extend ActiveSupport::Concern
MAX_PER_PAGE = 100
DEFAULT_PER_PAGE = 25
API Pagination Headers (Link + Total)
rails
pagination
rest-api
by codesnips
3 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
Share this code
Here's the card — post it anywhere.