NSUserDefaults - How to tell if a key exists
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In UserDefaults, checking whether a key exists is not the same as reading the stored value. Several typed getters return fallback values when the key is missing, which means a missing key and an intentionally stored default-like value can look identical unless you test for existence explicitly.
Why Typed Getters Are Not Enough
Methods such as bool(forKey:) and integer(forKey:) are convenient, but they do not tell you whether a key was ever written.
If those keys do not exist, the results are still false and 0. That behavior is helpful for simple reads but misleading when your logic depends on distinguishing missing data from stored data.
The Reliable Existence Check
To check whether a key exists, use object(forKey:) and compare the result to nil.
This works because object(forKey:) only returns nil when the key is absent. If the key exists, you get an object representation of the stored value.
Wrap It in a Small Helper
A helper method keeps call sites readable and reduces copy-pasted logic.
This is usually the best general-purpose answer for Swift codebases that interact with UserDefaults regularly.
Read the Typed Value After Checking Existence
When the distinction matters, check first and then read the typed value.
This is especially useful during onboarding flows, migrations, or feature-rollout logic where the first run must be handled differently from a real stored setting.
Keep Keys Centralized
Raw string keys are easy to mistype. A small enum or wrapper object makes the storage contract much safer.
Centralizing keys reduces accidental mismatches across different parts of the app.
dictionaryRepresentation() Is Usually Too Broad
You can also inspect all stored keys with dictionaryRepresentation(), but that is usually a debugging tool rather than the best existence check for production code.
This works, but it does more work than asking for one key directly. Use it when you want a broad inspection of stored values, not when you only need a single existence test.
Common Pitfalls
A common mistake is treating bool(forKey:) == false as proof that the key is missing. It may just mean the stored value is false.
Another mistake is using string(forKey:) as a universal existence check. That only works reliably if the stored type is actually a string.
Developers also forget that removeObject(forKey:) truly deletes the key. After removal, typed getters fall back to their default-return behavior again.
Summary
- Use
object(forKey:) != nilto test whether aUserDefaultskey exists. - Typed getters such as
bool(forKey:)andinteger(forKey:)do not prove key existence. - Check existence first when missing and stored default-like values must be distinguished.
- Wrap keys in an enum or helper to reduce string-typing mistakes.
- Treat
dictionaryRepresentation()as a debugging aid, not the default existence check.

