Skip to main content

iOS Code Review Checklist

Rapid-scan checklist for iOS code reviews. Use this to quickly identify issues, then dive into linked documentation for details.


Security Red Flags - Block PR Immediately

  • UserDefaults for secrets: Tokens, API keys in UserDefaults → Use Keychain
  • Hardcoded secrets: API keys, passwords in source code → Use build configuration or keychain
  • No certificate pinning: Production API without certificate pinning → Certificate Pinning
  • Sensitive data in logs: Tokens, account numbers, PINs in console logs → Never log sensitive data
  • Weak biometric context: Not checking biometric availability before authentication
  • HTTP instead of HTTPS: Cleartext traffic without App Transport Security exceptions
  • Keychain without accessibility attributes: Missing kSecAttrAccessibleWhenUnlockedThisDeviceOnly
  • Biometric data stored: Never store actual biometric data (use LocalAuthentication framework)
  • Root/jailbreak detection bypassed: No integrity checks for financial transactions
  • Screenshots enabled on sensitive views: No screenshot prevention on payment/auth screens

Common Mistakes

Architecture Violations

Memory Management

  • Strong reference cycles in closures → Use [weak self] or [unowned self]
  • Delegates not marked weak (retain cycles)
  • Timer not invalidated causing leaks
  • NotificationCenter observers not removed
  • @Published properties capturing self strongly
  • Combine subscriptions not stored (immediate deallocation)
  • Large images not released (memory warnings ignored)

SwiftUI Issues

  • State mutations not on main thread → Use @MainActor or DispatchQueue.main
  • @State used for non-view-local state → Use @StateObject or @ObservedObject
  • Creating ViewModels inline (= ViewModel()) instead of dependency injection
  • Side effects in view body (API calls during render)
  • Not using onAppear/onDisappear for lifecycle
  • Missing .task modifier for async operations
  • Unnecessary view updates (not using equatable or id)

Combine Issues

  • Subscriptions not stored in cancellables (leaks)
  • Not using receive(on: DispatchQueue.main) for UI updates
  • Infinite loops with circular publishers
  • Missing error handling in publisher chains
  • Using PassthroughSubject for state → Use CurrentValueSubject or @Published
  • Not cancelling subscriptions properly

Swift Issues

  • Force unwrapping (!) without justification → Use optional binding
  • Implicitly unwrapped optionals (String!) in non-IB contexts
  • Not using guard for early returns
  • Mutable variables (var) when let would work
  • Not handling Result type properly (ignoring errors)
  • Synchronous blocking on main thread
  • try! without error handling justification

Watch For - Performance & Correctness

Async/Await & Concurrency

  • Calling async functions without await
  • Not using Task for async operations in SwiftUI
  • Mixing completion handlers with async/await unnecessarily
  • Missing @MainActor on ViewModels → Main thread safety
  • Actor isolation violations
  • Data races in concurrent code
  • Not using AsyncSequence for streams

SwiftUI Performance

  • Heavy computation in view body (not in @State or .task)
  • Creating new view instances unnecessarily
  • Large lists not using LazyVStack/LazyHStack
  • Missing id in ForEach with complex data
  • Not using @ViewBuilder for conditional views
  • Excessive view hierarchy depth
  • Not leveraging @Binding for two-way state

Core Data Issues

  • Blocking fetch requests on main thread → Use perform/performAndWait
  • NSManagedObjectContext not thread-safe (used across threads)
  • Missing Core Data migrations
  • Fetching without NSFetchRequest batch size limit
  • Not using NSFetchedResultsController for table views
  • Entities with optional primitives (should be non-optional)

URLSession Issues

  • Not handling errors properly (ignoring failure responses)
  • Synchronous URLSession calls (blocks thread)
  • Not validating HTTP status codes
  • Missing timeout intervals
  • Certificate pinning not implemented → Certificate pinning
  • Not cancelling requests on view dismissal (leaks)

Best Practices - Code Quality

Clean Architecture

Modern iOS

  • SwiftUI for UI (not UIKit for new development) → SwiftUI guidelines
  • Combine or async/await for async operations → Combine
  • URLSession with async/await → Networking
  • Core Data for local persistence → Core Data
  • Swift concurrency (async/await, actors) → Concurrency
  • @MainActor for ViewModels

State Management

  • @Published properties in ViewModels → MVVM
  • @StateObject for ViewModel lifecycle management
  • @ObservedObject for passed ViewModels
  • @Binding for two-way data flow
  • Combine publishers for reactive streams
  • Result type for error handling

Security


Quick Scan Table

CategoryWhat to CheckSeverityReference
SecurityNo UserDefaults for secretsBlockKeychain
SecurityNo hardcoded API keysBlockSecurity
SecurityCertificate pinning implementedBlockCertificate Pinning
SecurityNo sensitive data in logsBlockSecurity
SecurityKeychain accessibility set properlyBlockKeychain
ArchitectureNo UIKit/SwiftUI in domainBlockClean Architecture
ArchitectureUse cases encapsulate logicFixUse Cases
ArchitectureRepository pattern implementedFixRepositories
ArchitectureNo business logic in ViewsFixMVVM
MemoryNo retain cycles in closuresFixUse [weak self]
MemoryDelegates marked weakFixMemory management
SwiftUIState updates on main threadFixUse @MainActor
SwiftUIViewModels via DIFixDI
SwiftUISide effects in proper lifecycleFixUse .task/.onAppear
CombineSubscriptions storedFixStore in cancellables
CombineUI updates on main threadFixreceive(on: .main)
GOOD:SwiftNo force unwrapping (!)Review
GOOD:SwiftPrefer let over varReview
Async@MainActor on ViewModelsFixThread safety
Core DataQueries not on main threadFixUse perform
URLSessionRequests cancelled properlyFixCancel on dismiss

Legend:

  • Block PR - Security vulnerability or architecture violation
  • Fix Before Merge - Correctness issue, performance problem, or likely bug
  • [GOOD] Review & Discuss - Code quality improvement

Additional Considerations

Xcode Project Configuration

  • Deployment target appropriate (iOS 16+ recommended)
  • Swift version consistent across targets
  • Build configuration optimized (Debug/Release)
  • Code signing configured properly
  • Info.plist privacy descriptions provided
  • App Transport Security configured
  • Bitcode disabled (deprecated)

Testing

  • Unit tests for ViewModels → Testing
  • Unit tests for Use Cases with mock repositories
  • SwiftUI view tests with ViewInspector
  • XCTest for domain logic
  • UI tests for critical flows (XCUITest)
  • Snapshot tests for UI consistency
  • Combine publishers tested

Accessibility

  • VoiceOver labels on all interactive elements
  • Dynamic Type support
  • Proper semantic properties in SwiftUI
  • Color contrast ratios meet WCAG AA
  • Touch targets minimum 44x44 points
  • Accessibility identifiers for UI tests

Localization

  • All strings in Localizable.strings
  • Plural strings with .stringsdict
  • Date/time formatted with locale
  • Currency formatted appropriately
  • RTL layout support
  • Region-specific formatting

Block Checklist - Must Fix Before Merge

  • No UserDefaults for secrets (use Keychain)
  • No hardcoded API keys or credentials
  • Certificate pinning for production APIs
  • No sensitive data in console logs
  • Keychain accessibility properly configured
  • No UIKit/SwiftUI dependencies in domain layer
  • Use cases encapsulate business logic
  • Repository pattern properly implemented
  • No strong reference cycles in closures ([weak self])
  • Delegates marked weak
  • SwiftUI state updates on main thread
  • Combine subscriptions stored in cancellables
  • No force unwrapping without justification
  • Async operations use async/await or Combine properly

iOS-Specific Testing Checklist

Before approving iOS PRs:

  • Unit tests for ViewModels → iOS Testing
  • Unit tests for Use Cases with mock repositories
  • SwiftUI view tests (ViewInspector or snapshot tests)
  • Core Data tests (in-memory store)
  • Combine publisher tests
  • Edge cases tested (nil, empty, error states)
  • Async/await tests with XCTest
  • No flaky tests (tests pass consistently)
  • Test coverage meets minimum threshold (80%+)
  • UI tests for critical user paths (XCUITest)

iOS Framework Guides:

Swift Language:

Cross-Platform:

Process: