Ang NSUserDefaults ay isang key-value data storage sa iOS, watchOS, tvOS at macOS, na idinisenyo para sa pag-save ng mga setting at configuration ng app. Ang data ay naka-imbak sa isang plist file sa sandbox ng app at awtomatikong nagsi-sync sa iCloud sa pamamagitan ng NSUbiquitousKeyValueStore. Ayon sa opisyal na dokumentasyon Apple Developer, 2025, sinusuportahan ng NSUserDefaults ang pag-imbak ng mga primitive na uri: String, Int, Bool, Float, Double, Data, Date, Array at Dictionary. Ang klase ay pinalitan ng pangalan sa UserDefaults simula noong Swift 3, ngunit ang Objective-C na pangalan nitong NSUserDefaults ay malawakang ginagamit pa rin sa codebase at dokumentasyon ng Apple.
Mga Pangunahing Punto
NSUserDefaults (UserDefaults sa Swift) ay isang built-in na mekanismo ng Apple para sa pag-imbak ng mga key-value pair sa plist format. Ito ay available sa lahat ng Apple platform: iOS, iPadOS, watchOS, tvOS at macOS. Ang pangunahing layunin — pag-save ng mga kagustuhan ng user, estado ng interface, first-launch flag, mga napiling opsyon at iba pang simpleng data na nananatili pagkatapos ng pag-restart ng app.
Ang bawat iOS app ay may nakahiwalay na sandbox, at ang NSUserDefaults ay naka-imbak sa direktoryo ng Library/Preferences sa loob ng sandbox na ito sa isang file na pinangalanang Bundle Identifier. Ang plist file ay naglalaman ng mga key-value pair, kung saan ang key ay isang string at ang value ay isa sa mga suportadong uri. Ang laki ng file ay hindi limitado, ngunit inirerekomenda ng Apple na mag-imbak lamang ng mga setting sa UserDefaults, hindi malalaking volume ng data.
Mula noong iOS 8, sinusuportahan ng NSUserDefaults ang App Groups — shared storage sa pagitan ng mga app ng parehong developer at kanilang mga extension (widget, watchOS companion apps). Para dito ginagamit ang initializer na init?(suiteName:) na may identifier ng App Group. Ito ay nagpapahintulot, halimbawa, sa isang widget sa Today screen na basahin ang mga setting mula sa pangunahing app nang hindi dini-duplicate ang logic ng pag-save.
Sa pisikal, ang NSUserDefaults ay naka-imbak sa isang binary plist file sa path: {Sandbox}/Library/Preferences/com.example.myapp.plist. Ang file ay gumagamit ng binary plist format (NSPropertyListBinaryFormat_v1_0) para sa compactness at bilis ng pagbasa. Sa macOS, ang file ay maaaring nasa XML format para sa compatibility. Hindi tulad ng SharedPreferences sa Android, ang mga plist file ng UserDefaults ay maaaring maglaman ng nested structures sa pamamagitan ng Dictionary at Array.
Ang mga file ng NSUserDefaults ay hindi naka-encrypt bilang default. Ang data ay naka-imbak sa bukas na anyo at maaaring basahin sa pisikal na access sa device o sa pamamagitan ng backup. Para sa pag-imbak ng sensitibong data (mga password, token, encryption key), mariing inirerekomenda ng Apple ang paggamit ng Keychain, na awtomatikong nag-e-encrypt ng data sa antas ng operating system.
Ang NSUserDefaults ay gumagana sa prinsipyo ng caching sa memory na may pana-panahong pag-sync sa disk. Sa unang pag-access sa standard instance na UserDefaults.standard, nilo-load ng system ang plist file sa RAM sa anyo ng Dictionary. Ang lahat ng kasunod na pagbasa ay ginagawa mula sa memory. Ang pagsulat ay ginagawa din muna sa memory, at ang pag-sync sa disk ay nagaganap nang pana-panahon sa background.
Ang mga operasyon ng pagsulat ay gumagamit ng paraang set(_:forKey:), na tumatanggap ng opsyonal na halaga ng uri na Any?. Ang halaga ay maaaring nil — para alisin ang key. Para sa agarang pagsulat sa disk, dating ginamit ang paraang synchronize(), ngunit mula noong iOS 7 at OS X 10.9 hindi na ito kinakailangan — awtomatikong nag-sync ang system ng data sa mga regular na pagitan. Opisyal na idineklara ng Apple na ang synchronize() ay redundant sa dokumentasyon nito.
Ang NSUserDefaults ay gumagamit ng sistema ng mga rehistro (domain) para sa pag-oorganisa ng paghahanap ng mga halaga. Kapag ang app ay humiling ng halaga ayon sa key, sunud-sunod na sinusuri ng UserDefaults ang mga domain sa isang tiyak na pagkakasunud-sunod: una NSArgumentDomain (mga argumento ng command line), pagkatapos ang domain ng app (Application), pagkatapos NSGlobalDomain (mga setting ng system), pagkatapos mga domain na partikular sa wika at sa wakas NSRegistrationDomain (mga default na halaga na nirehistro sa pamamagitan ng register(defaults:)).
import Foundation
// Standard na instance ng UserDefaults
let defaults = UserDefaults.standard
// Pagsulat ng mga halaga
defaults.set("Anna Petrova", forKey: "username")
defaults.set(28, forKey: "age")
defaults.set(true, forKey: "isLoggedIn")
// Pagrehistro ng mga default na halaga
defaults.register(defaults: [
"theme": "system",
"fontSize": 14
])
// Pagbasa na may pagbabalik ng default na halaga
let theme = defaults.string(forKey: "theme") ?? "system"
let fontSize = defaults.integer(forKey: "fontSize")
Ang domain na NSRegistrationDomain ay isang software domain na umiiral lamang sa RAM at hindi nai-save sa disk. Ito ay ginagamit upang magtakda ng mga default na halaga na aktibo hanggang sa isulat ng app ang sarili nitong halaga sa domain ng app. Ito ay nagpapahintulot sa paglikha ng isang solong punto ng configuration para sa mga default na setting na maaaring baguhin nang sentralisado sa yugto ng pag-develop.
Ang NSUserDefaults ay nagbibigay ng isang set ng mga na-type na pamamaraan para sa pagbasa at pagsulat ng data: string(forKey:), integer(forKey:), bool(forKey:), float(forKey:), double(forKey:), data(forKey:), array(forKey:), dictionary(forKey:) at object(forKey:). Ang bawat paraan ng pagbasa ay may kaukulang paraan ng pagsulat na set(_:forKey:) na may awtomatikong pagtukoy ng uri ng naka-imbak na halaga. Ang bersyon ng Swift ng UserDefaults ay gumagamit ng mahigpit na pag-type, ngunit ang bersyon ng Objective-C ay tumatanggap at nagbabalik ng id.
| Paraan ng pagbasa (Swift) | Uri ng data | Default na halaga |
|---|---|---|
| string(forKey:) | String? | nil |
| integer(forKey:) | Int | 0 |
| bool(forKey:) | Bool | false |
| float(forKey:) | Float | 0.0 |
| double(forKey:) | Double | 0.0 |
| data(forKey:) | Data? | nil |
Ang paraang synchronize() sa NSUserDefaults ay pinipilit ang pagsulat ng lahat ng pagbabago mula sa memory papunta sa disk. Sa mga unang bersyon ng iOS, ang paraang ito ay kailangang tawagan pagkatapos ng bawat pagsulat upang garantiyahan ang pag-save ng data. Mula noong iOS 7, awtomatikong nag-sync ang system ng UserDefaults sa background, at opisyal na idineklara ng Apple na ang synchronize() ay redundant. Ang pagtawag sa paraang ito ay hindi nagdudulot ng error, ngunit hindi nagbibigay ng anumang karagdagang garantiya ng pag-save.
Para sa pag-monitor ng mga pagbabago, ang NSUserDefaults ay nagbibigay ng notification na UserDefaults.didChangeNotification at KVO observation method na addObserver(_:forKeyPath:options:context:). Sa SwiftUI, available ang Property Wrapper na @AppStorage, na awtomatikong nag-sync ng value sa UserDefaults sa pag-update ng UI. Ang @AppStorage ay sumusuporta sa parehong uri ng UserDefaults at ito ang mas gustong paraan ng pagtatrabaho sa mga setting sa mga SwiftUI app.
// Pagmamasid ng mga pagbabago sa pamamagitan ng KVO
class SettingsViewModel: NSObject {
override func observeValue(
forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey: Any]?,
context: UnsafeMutableRawPointer?
) {
guard let keyPath else { return }
print("Nagbago ang key: \(keyPath)")
}
}
// SwiftUI - AppStorage
struct SettingsView: View {
@AppStorage("theme") private var theme: String = "system"
var body: some View {
Picker("Tema", selection: $theme) {
Text("Sistema").tag("system")
Text("Maliwanag").tag("light")
Text("Madilim").tag("dark")
}
}
}
Para sa pagtatrabaho sa App Groups (shared storage sa pagitan ng app at mga extension) ginagamit ang initializer na UserDefaults(suiteName:) na may identifier ng App Group. Halimbawa, "group.com.example.myapp". Ang data na nakasulat sa instance na ito ay accessible mula sa pangunahing app, widget, watchOS companion app at iba pang extension na kabilang sa parehong App Group. Ang bawat suite instance ay naka-imbak sa isang hiwalay na plist file.
Sa kabila ng kaginhawahan at pagiging simple, ang NSUserDefaults ay hindi isang unibersal na imbakan para sa lahat ng uri ng data sa iOS. Depende sa dami, kritikalidad at mga kinakailangan sa seguridad, ang Apple ay nagbibigay ng ilang alternatibo, bawat isa ay na-optimize para sa isang partikular na senaryo ng paggamit.
| Solusyon | Kailan gagamitin | Mga limitasyon |
|---|---|---|
| NSUserDefaults | Mga setting ng interface at configuration | Hindi angkop para sa malaking data at mga lihim |
| Keychain | Mga password, token, encryption key | Mas kumplikadong gamitin, mas mabagal |
| CoreData | Naka-structure na data na may relasyon | Labis para sa 10-20 setting |
| FileManager | Mga dokumento, larawan, binary data | Nangangailangan ng manu-manong pamamahala ng file |
| CloudKit | Cloud sync sa pagitan ng mga device | Nangangailangan ng iCloud account at network connection |
Ang Keychain ay isang protektadong imbakan ng Apple para sa kumpidensyal na data. Hindi tulad ng NSUserDefaults, lahat ng data sa Keychain ay naka-encrypt sa antas ng operating system gamit ang Secure Enclave hardware encryption sa mga katugmang device. Ang Keychain ay awtomatikong nagla-lock at nag-unlock kasama ng device at sumusuporta sa pagbabahagi ng access sa pagitan ng mga app ng parehong developer sa pamamagitan ng Keychain Access Groups.
Ang pangunahing disbentaha ng Keychain ay ang pagiging kumplikado ng API. Para sa simpleng pag-save ng isang string, kailangan gumawa ng SecItemAdd request na may pagtukoy ng mga attribute: klase (kSecClassGenericPassword), serbisyo (kSecAttrService), account (kSecAttrAccount) at ang data mismo (kSecValueData). Para sa pagpapasimple ng pagtatrabaho sa Keychain, may mga third-party wrapper tulad ng KeychainAccess at SwiftKeychainWrapper, na nagbibigay ng maginhawang key-value interface na katulad ng UserDefaults.
Tingnan natin ang isang praktikal na halimbawa: pag-save at pag-restore ng onboarding status (mga welcome screen) sa isang iOS app gamit ang NSUserDefaults. Sa unang paglunsad, nakikita ng user ang mga onboarding screen, pagkatapos na maipasa ang mga ito, ang isang flag ay nai-save sa UserDefaults. Sa mga susunod na paglunsad, ang onboarding ay nilalaktawan. Para sa SwiftUI ginagamit ang @AppStorage, para sa UIKit — direktang access sa UserDefaults.standard.
Gumawa tayo ng manager na OnboardingManager na nag-e-encapsulate ng pagtatrabaho sa UserDefaults para sa pag-imbak ng onboarding status. Ang manager ay nagbibigay ng property na isOnboardingCompleted para sa pagsusuri ng status at paraang markOnboardingCompleted para sa pagtatakda ng flag. Ang key para sa pag-imbak ay inilabas sa isang constant upang maiwasan ang mga typo. Para sa unit testing, ang manager ay gumagamit ng protocol na UserDefaultsProtocol, na nagpapahintulot na palitan ang tunay na imbakan ng MockUserDefaults.
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)
}
}
// Paggamit sa app
let onboardingManager = OnboardingManager()
if !onboardingManager.isOnboardingCompleted {
showOnboarding()
} else {
showMainScreen()
}
Para sa pag-imbak ng mas kumplikadong mga setting, tulad ng isang structured na Profile object, inirerekomenda ang paggamit ng Codable protocol at JSONEncoder/JSONDecoder. Ang object ay serialized sa Data sa pamamagitan ng JSONEncoder, nai-save sa pamamagitan ng set(_:forKey:), at kapag binabasa ay deserialized mula sa Data pabalik sa object sa pamamagitan ng JSONDecoder. Ang diskarteng ito ay nagpapahintulot sa pag-imbak ng mga kumplikadong istraktura sa UserDefaults nang walang pagkawala ng kaligtasan ng uri.
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)
}
}
// Paggamit
let profile = UserProfile(name: "Anna", age: 28, preferences: ["theme": "dark"])
UserDefaults.standard.save(profile, forKey: "user_profile")
let loaded = UserDefaults.standard.load(UserProfile.self, forKey: "user_profile")
Mahalagang tandaan na ang NSUserDefaults ay hindi dinisenyo para sa pag-imbak ng malalaking volume ng data. Inirerekomenda ng Apple na limitahan ang laki ng naka-imbak na data sa ilang sampung kilobytes. Para sa pag-imbak ng malalaking bagay (mga larawan, dokumento, serialized models) dapat gamitin ang FileManager na may Documents directory o CoreData. Bukod dito, hindi sinusuportahan ng UserDefaults ang versioning ng data schema — kapag nagbago ang istraktura ng Codable model, ang lumang data ay maaaring hindi ma-deserialize at ito ay kailangang hawakan sa code ng app.
Mga Madalas Itanong
Parehong key-value storage, ngunit ang NSUserDefaults ay sumusuporta sa mas maraming uri (Data, Date, Array, Dictionary) at awtomatikong nag-sync sa iCloud. Ang SharedPreferences ay nag-iimbak ng data sa XML, NSUserDefaults — sa plist format. Ang NSUserDefaults ay may sistema ng domain na may cascading search, ang SharedPreferences ay gumagamit ng simpleng flat structure na may mga pangalan ng file.
Hindi, ang NSUserDefaults ay nag-iimbak ng data sa bukas na anyo nang walang encryption. Para sa mga password, token at encryption key, gamitin ang Keychain, na nag-e-encrypt ng data sa antas ng Secure Enclave. Sinusuportahan din ng Keychain ang mga attribute ng access tulad ng biometric authentication (Face ID / Touch ID) bago basahin ang lihim.
Para sa pag-sync sa pagitan ng mga device ng parehong user, gamitin ang NSUbiquitousKeyValueStore — ang iCloud cloud key-value storage. Ang data na nakasulat sa serbisyong ito sa isang device ay awtomatikong lumalabas sa lahat ng iba pang device ng parehong iCloud account. Maximum na volume — 1 MB bawat app, 1024 na key.
Para tanggalin ang lahat ng data, tawagan ang paraang removePersistentDomain(forName:) na may Bundle Identifier ng app. Para sa pagtanggal ng mga indibidwal na halaga, gamitin ang removeObject(forKey:). Para sa kumpletong pag-reset ng mga setting ng app: UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!). Ang lahat ng pagtanggal ay agad na inilalapat sa memory cache.
Ang Apple ay hindi nagtatakda ng mahigpit na limitasyon para sa laki ng NSUserDefaults, ngunit inirerekomenda na huwag lumampas sa 100 KB para sa kabuuang dami ng lahat ng naka-imbak na data. Para sa malalaking volume, gamitin ang CoreData o FileManager. Kapag nag-iimbak ng higit sa 1 MB ng data, ang performance ng pagbasa sa paglunsad ng app ay maaaring kapansin-pansing bumaba.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din