You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
LDClient.didEnterBackground causes a main-thread hang of 5000+ ms by synchronously writing to NSUserDefaults during the background transition. This is affecting 653 users across 7,016 occurrences in our production app.
This is the same root cause reported in #398, which was closed without a code fix.
Environment
SDK versions affected: 9.12.2 and 11.1.1 (confirmed identical code path in both)
iOS versions: All tested — iOS 18.6.2 through 26.3.1
Devices: Primarily iPad (iPad13,19, iPad12,1, and others)
App: Enterprise sales enablement app deployed to managed iPad fleet
Reproduction
The hang occurs when the app transitions to background (Home button, app switch, or device lock). It requires concurrent NSUserDefaults access from other subsystems at the moment of backgrounding — common on MDM-managed devices and apps that use NSUserDefaults for caching.
NSUserDefaults.set internally calls -[NSOperation waitUntilFinished] → blocks on _pthread_cond_wait
The issue is that NSUserDefaults.set() can trigger a cross-process synchronization that blocks when the system is already coordinating the background transition. This is exacerbated on managed (MDM) devices where system-level NSUserDefaults observers add contention.
Summary
LDClient.didEnterBackgroundcauses a main-thread hang of 5000+ ms by synchronously writing toNSUserDefaultsduring the background transition. This is affecting 653 users across 7,016 occurrences in our production app.This is the same root cause reported in #398, which was closed without a code fix.
Environment
Reproduction
The hang occurs when the app transitions to background (Home button, app switch, or device lock). It requires concurrent
NSUserDefaultsaccess from other subsystems at the moment of backgrounding — common on MDM-managed devices and apps that useNSUserDefaultsfor caching.Root Cause
The full blocking call chain on the main thread:
UIApplication._applicationDidEnterBackgroundposts notificationLDClient.didEnterBackground(LDClient.swift:262) observes itNSThread.performOnMain→DispatchQueue.main.sync(Thread.swift)LDClient.runMode = .backgroundtriggeringdidSet(LDClient.swift:214)connectionInformationtriggeringdidSet(LDClient.swift:230)ConnectionInformationStore.storeConnectionInformation()(ConnectionInformationStore.swift:11)NSUserDefaults.save<T>→NSUserDefaults.set(KeyedValueCache.swift:15)NSUserDefaults.setinternally calls-[NSOperation waitUntilFinished]→ blocks on_pthread_cond_waitThe issue is that
NSUserDefaults.set()can trigger a cross-process synchronization that blocks when the system is already coordinating the background transition. This is exacerbated on managed (MDM) devices where system-levelNSUserDefaultsobservers add contention.Stacktrace (from Sentry)
Impact
Suggested Fix
Either of these would resolve the issue:
ConnectionInformationStore.storeConnectionInformation()asynchronous — dispatch theUserDefaults.setcall to a background queueThread.performOnMainindidEnterBackgroundto useDispatchQueue.main.asyncinstead ofDispatchQueue.main.syncNSUserDefaultsfor connection info persistence (related: Different Feature Flag Caching Mechanisms #316)Related Issues