iOS
Swift
NSUserDefaults
data storage
app development

Save string to the NSUserDefaults?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Saving a string to UserDefaults is one of the simplest kinds of iOS persistence. It works well for lightweight preferences and small pieces of state, but it is the wrong place for secrets, large data, or anything that behaves more like application data than a user preference.

Basic Save and Read Pattern

In modern Swift, use UserDefaults.standard:

swift
1import Foundation
2
3enum DefaultsKey {
4    static let welcomeMessage = "welcomeMessage"
5}
6
7func saveWelcomeMessage(_ message: String) {
8    UserDefaults.standard.set(message, forKey: DefaultsKey.welcomeMessage)
9}
10
11func loadWelcomeMessage() -> String? {
12    UserDefaults.standard.string(forKey: DefaultsKey.welcomeMessage)
13}
14
15saveWelcomeMessage("Hello, World!")
16print(loadWelcomeMessage() ?? "No message")

This stores a string under a stable key and retrieves it later.

Prefer Stable Keys and Small Helpers

Raw string keys scattered throughout the codebase lead to typos and migration problems. A helper keeps things centralized:

swift
1import Foundation
2
3final class AppPreferences {
4    private let defaults = UserDefaults.standard
5
6    private enum Key {
7        static let username = "username"
8    }
9
10    var username: String {
11        get { defaults.string(forKey: Key.username) ?? "" }
12        set { defaults.set(newValue, forKey: Key.username) }
13    }
14}

This also makes it easier to rename or migrate keys later.

Handle Missing Values Intentionally

A missing key is not always the same thing as an empty string. Sometimes you want a fallback:

swift
let city = UserDefaults.standard.string(forKey: "city") ?? "Toronto"

And sometimes you want to know whether the value was ever set:

swift
1let city = UserDefaults.standard.string(forKey: "city")
2if city == nil {
3    // first launch or value not stored yet
4}

Choosing deliberately between optional behavior and a default value keeps UI and analytics logic clearer.

Update and Remove Values

Writing the same key again updates the stored value:

swift
UserDefaults.standard.set("Updated", forKey: "welcomeMessage")

To remove the key:

swift
UserDefaults.standard.removeObject(forKey: "welcomeMessage")

This is common in reset flows and logout handling.

Know What Belongs in UserDefaults

Good candidates:

  • onboarding flags
  • last selected tab or filter
  • theme preferences
  • non-sensitive small strings such as a display preference

Bad candidates:

  • passwords or tokens
  • large text blobs
  • images
  • frequently changing high-volume data

Use the Keychain for secrets and a file or database layer for larger or more structured data.

App Groups for Shared Values

If an app and its extension need to share the same value, use a suite backed by an app group:

swift
if let sharedDefaults = UserDefaults(suiteName: "group.com.example.app") {
    sharedDefaults.set("shared value", forKey: "sharedKey")
}

Without the app group configuration, the main app and extension have separate defaults containers.

Testing and Key Migration

In tests, avoid polluting the real defaults store. Use a suite-specific store instead:

swift
let testDefaults = UserDefaults(suiteName: "test-suite")
testDefaults?.set("abc", forKey: "k")

When renaming keys, migrate once:

swift
1let oldKey = "oldName"
2let newKey = "newName"
3
4if let value = UserDefaults.standard.string(forKey: oldKey) {
5    UserDefaults.standard.set(value, forKey: newKey)
6    UserDefaults.standard.removeObject(forKey: oldKey)
7}

That avoids silently losing settings during app updates.

Common Pitfalls

  • Storing secrets in UserDefaults instead of the Keychain.
  • Scattering raw string keys across the codebase and introducing typos.
  • Treating missing values and empty strings as if they always mean the same thing.
  • Storing large or frequently changing data and turning a preference store into a poor database.
  • Forgetting suite configuration when data must be shared with extensions.

Summary

  • 'UserDefaults is fine for lightweight non-sensitive strings and preferences.'
  • Save with set(_:forKey:) and read with typed accessors such as string(forKey:).
  • Centralize keys instead of duplicating raw string literals everywhere.
  • Use Keychain for secrets and other storage for larger data.
  • Use app-group suites when app extensions need to share values.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.