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: