DOMAIN:IOS_DEVELOPMENT:PITFALLS¶
OWNER: martijn
ALSO_USED_BY: valentin
UPDATED: 2026-03-24
PITFALL:SIGNING_IDENTITY_CONFUSION¶
SYMPTOM: "No signing certificate found" or "Provisioning profile doesn't match"
CAUSE: multiple Apple Developer accounts in Keychain, or cert/key mismatch
FIX: security find-identity -v -p codesigning to list all identities
FIX: delete old/expired certs from Keychain Access
FIX: ensure private key exists alongside certificate
FIX: use Fastlane match to centralize signing
PITFALL:DEVICE_UDID_LIMIT¶
SYMPTOM: cannot add more test devices to Ad Hoc profile
CAUSE: 100 device limit per device type per membership year
RULE: removing a device does NOT free the slot until renewal
FIX: use TestFlight instead — no device limit
FIX: plan device registrations at start of year
PITFALL:BACKGROUND_TASK_NOT_RUNNING¶
SYMPTOM: BGTaskScheduler tasks never execute
CAUSE: multiple possible causes
CHECK: is the task identifier registered in Info.plist BGTaskSchedulerPermittedIdentifiers?
CHECK: is BGTaskScheduler.shared.register() called in didFinishLaunchingWithOptions?
CHECK: is the device plugged in? (BGProcessingTask requires charging)
CHECK: did you call task.setTaskCompleted(success:) in the handler?
DEBUG: e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.app.refresh"] in Xcode debugger
PITFALL:ATS_BLOCKING_REQUESTS¶
SYMPTOM: network requests silently fail or return ATS error
CAUSE: HTTP URL or TLS < 1.2
FIX: use HTTPS everywhere
FIX: if legacy server, add per-domain exception in Info.plist (never global)
CHECK: Console.app → filter "ATS" to see blocked requests
PITFALL:PUSH_TOKEN_MISMATCH¶
SYMPTOM: push notifications work in development but not production
CAUSE: sandbox vs production APNs environments use different tokens
FIX: ensure backend sends to correct APNs endpoint based on build type
FIX: use APNs authentication key (.p8) — works for both environments
CHECK: is aps-environment entitlement set correctly? (development vs production)
PITFALL:MEMORY_PRESSURE_CRASHES¶
SYMPTOM: app crashes without crash log (jetsam termination)
CAUSE: excessive memory usage
CHECK: Xcode Organizer → Terminations → Memory
CHECK: Instruments → Allocations
FIX: downsample images to display size
FIX: release caches in didReceiveMemoryWarning
FIX: use autorelease pool for batch operations
FIX: lazy load heavy resources
PITFALL:RETAIN_CYCLES¶
SYMPTOM: memory grows over time, view controllers not deallocated
CAUSE: strong reference cycle (usually in closures or delegates)
FIX: [weak self] in escaping closures
FIX: weak var delegate in delegation pattern
FIX: use Xcode Memory Graph Debugger to find cycles
CHECK: add deinit { print("VC deallocated") } during development to verify cleanup
PITFALL:APP_STORE_REJECTION_LOOP¶
SYMPTOM: app rejected repeatedly for same or different issues
CAUSE: fixing one issue reveals another, or fix doesn't address reviewer's concern
FIX: read rejection message CAREFULLY — match specific guideline number
FIX: reply in Resolution Center asking for clarification if ambiguous
FIX: do NOT submit identical build hoping for different reviewer
ESCALATE_TO: human after 3 rejections — may need Apple Developer Relations call
PITFALL:SWIFTUI_LIST_PERFORMANCE¶
SYMPTOM: scrolling stutters with large lists
CAUSE: non-lazy views, complex view bodies, unnecessary redraws
FIX: use List or LazyVStack — NOT VStack for dynamic content
FIX: extract subviews to reduce body complexity
FIX: use @Observable macro (iOS 17+) — finer-grained updates than ObservableObject
FIX: avoid computing complex values in view body — move to view model
CHECK: Instruments → SwiftUI instrumentation
PITFALL:DYNAMIC_TYPE_BROKEN_LAYOUT¶
SYMPTOM: UI breaks at large/accessibility text sizes
CAUSE: fixed-height constraints, images competing with text
FIX: use text styles (.font(.body)) not fixed sizes
FIX: use flexible layouts (no fixed heights on text containers)
FIX: test at ALL Dynamic Type sizes including the 5 accessibility sizes
TOOL: Xcode → Environment Overrides → Dynamic Type slider
PITFALL:DARK_MODE_INVISIBLE_ELEMENTS¶
SYMPTOM: elements invisible or unreadable in dark mode
CAUSE: hardcoded colors (Color.white, Color.black, hex values)
FIX: use semantic colors (Color(.label), Color(.systemBackground))
FIX: define custom colors in Asset Catalog with dark mode variants
CHECK: toggle Appearance in Xcode preview or Environment Overrides
PITFALL:KEYBOARD_COVERS_INPUT¶
SYMPTOM: keyboard appears and covers the text field user is typing in
CAUSE: no keyboard avoidance
FIX: SwiftUI automatically adjusts for keyboard in ScrollView/List (iOS 15+)
FIX: for custom layouts, use KeyboardLayoutGuide (UIKit) or .scrollDismissesKeyboard(.interactively)
FIX: add .scrollDismissesKeyboard(.interactively) to ScrollView for dismiss-on-drag
PITFALL:EXPIRED_ENTERPRISE_CERT¶
SYMPTOM: all enterprise-distributed apps stop launching
CAUSE: enterprise distribution certificate expired or revoked
SEVERITY: CRITICAL — affects ALL apps signed with that cert across entire organization
FIX: renew certificate 30 days before expiry
FIX: re-sign and redistribute all apps
FIX: set calendar reminders for cert expiry
NOTE: Apple enterprise certs are valid for 3 years but provisioning profiles expire annually
PITFALL:PRIVACY_MANIFEST_MISSING¶
SYMPTOM: App Store Connect warning or rejection about missing privacy manifest
CAUSE: app or included SDK missing PrivacyInfo.xcprivacy
FIX: add PrivacyInfo.xcprivacy to app target
FIX: declare all required reason API usage
FIX: ensure all third-party SDKs include their own manifests
TOOL: Xcode → Product → Generate Privacy Report
CHECK: run privacy report before every submission
PITFALL:SIMULATOR_VS_DEVICE_DIFFERENCES¶
SYMPTOM: works in Simulator but not on device (or vice versa)
CAUSE: Simulator lacks hardware features + has different performance characteristics
| Feature | Simulator | Device |
|---|---|---|
| Camera | Not available | Available |
| Push notifications | Not available (APNs) | Available |
| Bluetooth | Not available | Available |
| GPS | Simulated only | Real |
| Performance | Host machine CPU | A-series/M-series chip |
| Memory | Host machine RAM | Device-limited |
| Biometrics | Simulated | Real Face ID/Touch ID |
| Network | Host network | Cellular/Wi-Fi |
RULE: ALWAYS test on real device before submission
RULE: test on oldest supported device if possible
RULE: test on device with minimal storage (low disk space handling)