• Blog
  • Categories
    • App Store
    • Benchmarks
    • iOS
    • Objective-C
    • OS X
    • PHP
    • RV
    • Swift
    • tvOS
    • Web
  • Apps
    • Portfolio
    • Studio Pro
    • Sun & Moon
  • Photography

Projects

Remote Working, iOS, Mac OS X, and more

OS X

NSUserDefaults Stops Functioning

While working on a project for a client (updating an OS X app), we ran into a problem that we first thought was a bug in the app itself. Entire portions of the interface were completely non-functional but only on the client’s machine. I inherited large portions of technical debt with the project, so I figured it was just something in there.

Bug troubleshooting seems like it’s 95% luck at times, especially when the conditions for reproducing it seem totally random. This was one of those cases — everything I started on ended up as a dead end. After a couple days, it was only out of pure dumb luck that I stumbled on the recipe to reproduce the problem: uninstall the previous version of the app. A full uninstall.

Sandboxed apps store their data at ~/Library/Containers/\. Fully uninstalling an app means deleting the preferences and then the stored data at that path, whether it’s done by hand or using a tool. This is exactly what my client was doing between builds, and it’s what triggered this bug.

The Underlying Behavior

At least as far back as OS X 10.9 (Mavericks), OS X has been caching preferences using a daemon process called cfprefsd. This process mediates access to the preferences system and holds on to an open file descriptor for each property list accessed, presumably to speed up access.

Screenshot of cfprefsd

cfprefsd does not seem to monitor the property list files for any external changes though — it assumes it will be the only process accessing them. Further, running the Terminal command defaults delete com.example.myapp doesn’t actually delete the preferences file. Instead, it sets the contents to an empty property list and leaves the file descriptor open.

The Result

By deleting the entire group container for the app, this also deletes the file system entry for the preferences file. Rather than re-create the file, cfprefsd holds on to a stale file descriptor. All calls to read or set values via NSUserDefaults then turn into no-ops, and the only way to force restoration of the correct behavior is to restart cfprefsd: reboot the system or killall cfprefsd.

Radar #24217396.

Previous
Next

Copyright 2025 Ryan Britton