NSUserDefaults — что это, UserDefaults API и работа с настройками iOS

Автор: IT Sectr Опубликовано: 2026-03-12 Время чтения: 10 мин

NSUserDefaults — это ключ-значение хранилище данных в iOS, watchOS, tvOS и macOS, предназначенное для сохранения настроек и конфигураций приложения. Данные хранятся в plist-файле в песочнице приложения и автоматически синхронизируются с iCloud через NSUbiquitousKeyValueStore. Согласно официальной документации Apple Developer, 2025, NSUserDefaults поддерживает хранение примитивных типов: String, Int, Bool, Float, Double, Data, Date, Array и Dictionary. Класс переименован в UserDefaults начиная с Swift 3, но его Objective-C имя NSUserDefaults остаётся широко используемым в кодовой базе и документации Apple.

Главное

  • NSUserDefaults — ключ-значение хранилище на iOS и macOS для сохранения простых настроек приложения в plist-файле.
  • Поддерживает девять типов данных: String, Int, Bool, Float, Double, Data, Date, Array и Dictionary.
  • Данные автоматически синхронизируются с iCloud через NSUbiquitousKeyValueStore при поддержке со стороны разработчика.
  • Использует систему регистров (доменов) с каскадным поиском значения по цепочке доменов.
  • Для хранения чувствительных данных Apple рекомендует использовать Keychain вместо NSUserDefaults.

Что такое NSUserDefaults?

NSUserDefaults (UserDefaults в Swift) — это встроенный механизм Apple для хранения пар ключ-значение в plist-формате. Он доступен на всех платформах Apple: iOS, iPadOS, watchOS, tvOS и macOS. Основное назначение — сохранение пользовательских предпочтений, состояния интерфейса, флагов first-launch, выбранных опций и других простых данных, которые переживают перезапуск приложения.

Каждое приложение iOS имеет изолированную песочницу, и NSUserDefaults хранится в директории Library/Preferences внутри этой песочницы в файле с именем Bundle Identifier. plist-файл содержит пары ключ-значение, где ключом выступает строка, а значением — один из поддерживаемых типов. Размер файла не ограничен, но Apple рекомендует хранить в UserDefaults только настройки, а не большие объёмы данных.

Начиная с iOS 8, NSUserDefaults стал поддерживать App Groups — общее хранилище между приложениями одного разработчика и их расширениями (widgets, watchOS companion apps). Для этого используется инициализатор init?(suiteName:) с идентификатором App Group. Это позволяет, например, виджету на экране Today читать настройки из основного приложения без дублирования логики сохранения.

Формат хранения: plist на устройстве

Физически NSUserDefaults хранится в бинарном plist-файле по пути: {Sandbox}/Library/Preferences/com.example.myapp.plist. Файл использует бинарный формат plist (NSPropertyListBinaryFormat_v1_0) для компактности и скорости чтения. В macOS файл может быть в XML-формате для совместимости. В отличие от SharedPreferences на Android, plist-файлы UserDefaults могут содержать вложенные структуры через Dictionary и Array.

Файлы NSUserDefaults не шифруются по умолчанию. Данные хранятся в открытом виде и могут быть прочитаны при физическом доступе к устройству или через резервную копию. Для хранения чувствительных данных (пароли, токены, ключи шифрования) Apple категорически рекомендует использовать Keychain, который автоматически шифрует данные на уровне операционной системы.

Как работает NSUserDefaults в iOS

NSUserDefaults работает по принципу кэширования в памяти с периодической синхронизацией на диск. При первом обращении к стандартному экземпляру UserDefaults.standard система загружает plist-файл в оперативную память в виде Dictionary. Все последующие чтения выполняются из памяти. Запись также сначала производится в память, а синхронизация на диск происходит периодически в фоновом потоке.

Операции записи используют метод set(_:forKey:), который принимает значение опционального типа Any?. Значение может быть nil — для удаления ключа. Для немедленной записи на диск ранее использовался метод synchronize(), но начиная с iOS 7 и OS X 10.9 он больше не требуется — система автоматически синхронизирует данные через регулярные промежутки времени. Apple официально объявила synchronize() избыточным в своей документации.

Регистры UserDefaults и домены

NSUserDefaults использует систему регистров (доменов) для организации поиска значений. Когда приложение запрашивает значение по ключу, UserDefaults последовательно проверяет домены в определённом порядке: сначала NSArgumentDomain (аргументы командной строки), затем домен приложения (Application), затем NSGlobalDomain (системные настройки), затем Language-specific домены и наконец NSRegistrationDomain (значения по умолчанию, зарегистрированные через register(defaults:)).

swift
import Foundation

// Стандартный экземпляр UserDefaults
let defaults = UserDefaults.standard

// Запись значений
defaults.set("Анна Петрова", forKey: "username")
defaults.set(28, forKey: "age")
defaults.set(true, forKey: "isLoggedIn")

// Регистрация значений по умолчанию
defaults.register(defaults: [
    "theme": "system",
    "fontSize": 14
])

// Чтение с возвратом значения по умолчанию
let theme = defaults.string(forKey: "theme") ?? "system"
let fontSize = defaults.integer(forKey: "fontSize")

Домен NSRegistrationDomain — это программный домен, который существует только в оперативной памяти и не сохраняется на диск. Он используется для задания значений по умолчанию, которые действуют, пока приложение не запишет своё значение в домен приложения. Это позволяет создать единую точку конфигурации дефолтных настроек, которые можно централизованно менять на этапе разработки.

Основные методы NSUserDefaults

NSUserDefaults предоставляет набор типизированных методов для чтения и записи данных: string(forKey:), integer(forKey:), bool(forKey:), float(forKey:), double(forKey:), data(forKey:), array(forKey:), dictionary(forKey:) и object(forKey:). Каждый метод чтения имеет соответствующий метод записи set(_:forKey:) с автоматическим определением типа сохраняемого значения. Swift-версия UserDefaults использует строгую типизацию, но Objective-C версия принимает и возвращает id.

Метод чтения (Swift)Тип данныхЗначение по умолчанию
string(forKey:)String?nil
integer(forKey:)Int0
bool(forKey:)Boolfalse
float(forKey:)Float0.0
double(forKey:)Double0.0
data(forKey:)Data?nil

synchronize и его актуальность

Метод synchronize() в NSUserDefaults принудительно записывает все изменения из памяти на диск. В ранних версиях iOS этот метод было необходимо вызывать после каждой записи для гарантии сохранения данных. Начиная с iOS 7, система автоматически синхронизирует UserDefaults в фоновом потоке, и Apple официально объявила synchronize() избыточным. Вызов этого метода не приводит к ошибке, но не даёт никаких гарантий дополнительной сохранности.

Для мониторинга изменений NSUserDefaults предоставляет уведомление UserDefaults.didChangeNotification и метод KVO-наблюдения addObserver(_:forKeyPath:options:context:). В SwiftUI доступен Property Wrapper @AppStorage, который автоматически синхронизирует значение в UserDefaults с обновлением UI. @AppStorage поддерживает те же типы, что и UserDefaults, и является предпочтительным способом работы с настройками в SwiftUI-приложениях.

swift
// Наблюдение изменений через KVO
class SettingsViewModel: NSObject {
    override func observeValue(
        forKeyPath keyPath: String?,
        of object: Any?,
        change: [NSKeyValueChangeKey: Any]?,
        context: UnsafeMutableRawPointer?
    ) {
        guard let keyPath else { return }
        print("Изменился ключ: \(keyPath)")
    }
}

// SwiftUI - AppStorage
struct SettingsView: View {
    @AppStorage("theme") private var theme: String = "system"

    var body: some View {
        Picker("Тема", selection: $theme) {
            Text("Системная").tag("system")
            Text("Светлая").tag("light")
            Text("Тёмная").tag("dark")
        }
    }
}

Для работы с App Groups (общее хранилище между приложением и расширениями) используется инициализатор UserDefaults(suiteName:) с идентификатором App Group. Например, "group.com.example.myapp". Данные, записанные в этот экземпляр, доступны из основного приложения, виджета, watchOS companion приложения и других расширений, принадлежащих одному App Group. Каждый экземпляр suite хранится в отдельном plist-файле.

NSUserDefaults vs альтернативы хранения

Несмотря на удобство и простоту, NSUserDefaults не является универсальным хранилищем для всех типов данных на iOS. В зависимости от объёма, критичности и требований к безопасности, Apple предоставляет несколько альтернатив, каждая из которых оптимизирована под конкретный сценарий использования.

РешениеКогда использоватьОграничения
NSUserDefaultsНастройки интерфейса и конфигурацияНе подходит для больших данных и секретов
KeychainПароли, токены, ключи шифрованияСложнее в использовании, медленнее
CoreDataСтруктурированные данные со связямиИзбыточен для 10-20 настроек
FileManagerДокументы, изображения, бинарные данныеТребует ручного управления файлами
CloudKitОблачная синхронизация между устройствамиТребует iCloud аккаунта и сетевого соединения

Keychain — безопасное хранение

Keychain — это защищённое хранилище Apple для конфиденциальных данных. В отличие от NSUserDefaults, все данные в Keychain шифруются на уровне операционной системы с использованием аппаратного шифрования Secure Enclave на совместимых устройствах. Keychain автоматически блокируется и разблокируется вместе с устройством и поддерживает разделение доступа между приложениями одного разработчика через Keychain Access Groups.

Основной недостаток Keychain — сложность API. Для простого сохранения строки требуется создать запрос SecItemAdd с указанием атрибутов: класса (kSecClassGenericPassword), сервиса (kSecAttrService), аккаунта (kSecAttrAccount) и собственно данных (kSecValueData). Для упрощения работы с Keychain существуют сторонние обёртки, такие как KeychainAccess и SwiftKeychainWrapper, которые предоставляют удобный ключ-значение интерфейс, аналогичный UserDefaults.

Пример использования NSUserDefaults в Swift

Рассмотрим практический пример: сохранение и восстановление состояния онбординга (экранов приветствия) в iOS-приложении с использованием NSUserDefaults. При первом запуске пользователь видит экраны онбординга, после прохождения которых флаг сохраняется в UserDefaults. При последующих запусках онбординг пропускается. Для SwiftUI используется @AppStorage, для UIKit — прямой доступ к UserDefaults.standard.

Сохранение состояния онбординга

Создадим менеджер OnboardingManager, который инкапсулирует работу с UserDefaults для хранения статуса онбординга. Менеджер предоставляет свойство isOnboardingCompleted для проверки состояния и метод markOnboardingCompleted для установки флага. Ключ для хранения вынесен в константу для предотвращения опечаток. Для unit-тестирования менеджер использует протокол UserDefaultsProtocol, что позволяет подменить реальное хранилище на MockUserDefaults.

swift
class OnboardingManager {
    private let defaults: UserDefaults
    private let hasSeenKey = "has_seen_onboarding"

    init(defaults: UserDefaults = .standard) {
        self.defaults = defaults
    }

    var isOnboardingCompleted: Bool {
        defaults.bool(forKey: hasSeenKey)
    }

    func markOnboardingCompleted() {
        defaults.set(true, forKey: hasSeenKey)
    }

    func resetOnboarding() {
        defaults.removeObject(forKey: hasSeenKey)
    }
}

// Использование в приложении
let onboardingManager = OnboardingManager()
if !onboardingManager.isOnboardingCompleted {
    showOnboarding()
} else {
    showMainScreen()
}

Для хранения более сложных настроек, таких как структурированный объект Profile, рекомендуется использовать Codable протокол и JSONEncoder/JSONDecoder. Объект сериализуется в Data через JSONEncoder, сохраняется через set(_:forKey:), и при чтении десериализуется из Data обратно в объект через JSONDecoder. Этот подход позволяет хранить в UserDefaults сложные структуры без потери типобезопасности.

swift
struct UserProfile: Codable {
    let name: String
    let age: Int
    let preferences: [String: String]
}

extension UserDefaults {
    func save<T: Codable>(_ value: T, forKey key: String) {
        if let data = try? JSONEncoder().encode(value) {
            set(data, forKey: key)
        }
    }

    func load<T: Codable>(_ type: T.Type, forKey key: String) -> T? {
        guard let data = data(forKey: key) else { return nil }
        return try? JSONDecoder().decode(type, from: data)
    }
}

// Использование
let profile = UserProfile(name: "Анна", age: 28, preferences: ["theme": "dark"])
UserDefaults.standard.save(profile, forKey: "user_profile")
let loaded = UserDefaults.standard.load(UserProfile.self, forKey: "user_profile")

Важно помнить, что NSUserDefaults не предназначен для хранения больших объёмов данных. Apple рекомендует ограничивать размер хранимых данных несколькими десятками килобайт. Для хранения больших объектов (изображений, документов, сериализованных моделей) следует использовать FileManager с директорией Documents или CoreData. Кроме того, UserDefaults не поддерживает версионирование схемы данных — при изменении структуры Codable-модели старые данные могут не десериализоваться, и это нужно обрабатывать в коде приложения.

Часто задаваемые вопросы

Чем NSUserDefaults отличается от SharedPreferences на Android?

Оба являются ключ-значение хранилищами, но NSUserDefaults поддерживает больше типов (Data, Date, Array, Dictionary) и автоматически синхронизируется с iCloud. SharedPreferences хранит данные в XML, NSUserDefaults — в plist-формате. NSUserDefaults имеет систему доменов с каскадным поиском, SharedPreferences использует простую плоскую структуру с именами файлов.

Безопасно ли хранить пароли в NSUserDefaults?

Нет, NSUserDefaults хранит данные в открытом виде без шифрования. Для паролей, токенов и ключей шифрования используйте Keychain, который шифрует данные на уровне Secure Enclave. Keychain также поддерживает атрибуты доступа, такие как биометрическая аутентификация (Face ID / Touch ID) перед чтением секрета.

Как синхронизировать NSUserDefaults между устройствами?

Для синхронизации между устройствами одного пользователя используйте NSUbiquitousKeyValueStore — облачное ключ-значение хранилище iCloud. Данные, записанные в этот сервис на одном устройстве, автоматически появляются на всех других устройствах того же iCloud-аккаунта. Максимальный объём — 1 MB на приложение, 1024 ключа.

Как удалить все данные из NSUserDefaults?

Для удаления всех данных вызовите метод removePersistentDomain(forName:) с Bundle Identifier приложения. Для удаления отдельных значений используйте removeObject(forKey:). Для полного сброса настроек приложения: UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!). Все удаления применяются немедленно к in-memory кэшу.

Какой максимальный размер данных в NSUserDefaults?

Apple не устанавливает жёсткого лимита на размер NSUserDefaults, но рекомендуется не превышать 100 KB на общий объём всех хранимых данных. Для больших объёмов используйте CoreData или FileManager. При хранении более 1 MB данных производительность чтения при запуске приложения может заметно снизиться.

Итоги

  • NSUserDefaults — встроенное ключ-значение хранилище Apple для простых настроек приложения в plist-формате.
  • Поддерживает девять типов данных: String, Int, Bool, Float, Double, Data, Date, Array и Dictionary.
  • Использует систему доменов с каскадным поиском через NSRegistrationDomain, NSGlobalDomain и домен приложения.
  • Для синхронизации между устройствами Apple предоставляет NSUbiquitousKeyValueStore с лимитом 1 MB на приложение.
  • Для безопасности используйте Keychain для паролей и токенов, а не NSUserDefaults.
  • В SwiftUI предпочтительный способ работы — Property Wrapper @AppStorage с автоматической синхронизацией UI.
  • Для больших или структурированных данных выбирайте CoreData или FileManager вместо NSUserDefaults.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также