Як зберегти місцеві дані в додатку Swift?


148

Зараз я працюю над додатком для iOS, розробленим у Swift, і мені потрібно зберігати на пристрої деякий створений користувачем вміст, але я не можу знайти простий і швидкий спосіб зберігати / отримувати вміст користувачів на пристрої.

Може хтось пояснить, як зберігати та отримувати доступ до локального сховища?

Ідея полягає в тому, щоб зберігати дані, коли користувач виконує дію, і отримувати їх при запуску програми.


Привіт, ласкаво просимо, які дані ви зберігаєте? Чи можете ви надати який-небудь код, щоб навести приклад того, що ви шукаєте? Дякую.
Вец

1
Дані, які мені потрібно зберігати, це в основному лише рядкові дані. Отже, щоб зробити це дійсно просто, мені потрібно зберегти два значення String, які я можу отримати, якщо користувач перезапустить додаток.
Nicklas Ridewing

2
Ви можете використовувати параметри NSUserDefaults. Ось інформація, яка вам потрібна codingexplorer.com/nsuserdefaults-a-swift-introduction
bpolat

Відповіді:


197

Найпростіше рішення, якщо ви просто зберігаєте два рядки, - NSUserDefaultsу Swift 3 цей клас було перейменовано на just UserDefaults.

Найкраще зберігати ключі десь у всьому світі, щоб ви могли повторно їх використовувати в іншому місці коду.

struct defaultsKeys {
    static let keyOne = "firstStringKey"
    static let keyTwo = "secondStringKey"
}

Swift 3.0, 4.0 та 5.0

// Setting

let defaults = UserDefaults.standard
defaults.set("Some String Value", forKey: defaultsKeys.keyOne)
defaults.set("Another String Value", forKey: defaultsKeys.keyTwo)

// Getting

let defaults = UserDefaults.standard
if let stringOne = defaults.string(forKey: defaultsKeys.keyOne) {
    print(stringOne) // Some String Value
}
if let stringTwo = defaults.string(forKey: defaultsKeys.keyTwo) {
    print(stringTwo) // Another String Value
}

Швидкий 2.0

// Setting

let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("Some String Value", forKey: defaultsKeys.keyOne)
defaults.setObject("Another String Value", forKey: defaultsKeys.keyTwo)

// Getting

let defaults = NSUserDefaults.standardUserDefaults()
if let stringOne = defaults.stringForKey(defaultsKeys.keyOne) {
    print(stringOne) // Some String Value
}
if let stringTwo = defaults.stringForKey(defaultsKeys.keyTwo) {
    print(stringTwo) // Another String Value
}

Для нічого більш серйозного, ніж незначні конфігурації, прапори або базові рядки, ви повинні використовувати якийсь стійкий магазин - Наразі популярним варіантом є Realm, але ви також можете використовувати SQLite або Apples з власним CoreData .


7
Гарний приклад. Це, мабуть, має бути перерахунком замість структури.
сканування та сканування

3
Це дивна реалізація enum, якщо у вас просто статичні константи, це може бути також структура.
Крейг Груммітт

1
Цей код неправильний. Не використовуйте методи KVC setValue(_:forKey:)для збереження даних у UserDefaults. Використовуйте надані UserDefaultsметоди set(_:forKey:)(у Swift 3).
rmaddy

Я оновив код Swift 3. Я не знаю, яким повинен бути синтаксис Swift 2.
rmaddy

@rmaddy це добре, як є.
Вез

57

Вони кажуть, що використовують NSUserDefaults

Коли я вперше впроваджував тривале (після закриття програми) зберігання даних, все, що я читав в Інтернеті, вказувало на NSUserDefaults. Однак я хотів зберігати словник, і, хоча це було можливо, це виявляло біль. Я витрачав години, намагаючись отримати помилки типу, щоб піти.

NSUserDefaults також обмежений у функції

Подальше читання показало, як читання / запис NSUserDefaults насправді змушує програму читати / писати все або нічого, і все відразу, тому це не ефективно. Тоді я дізнався, що отримання масиву не є прямим вперед. Я зрозумів, що якщо ви зберігаєте більше декількох рядків або булів, NSUserDefaults насправді не ідеально.

Це також не масштабується. Якщо ви навчитеся кодувати, вивчіть масштабований спосіб. Використовуйте лише NSUserDefaults для зберігання простих рядків або булів, пов’язаних із налаштуваннями. Зберігайте масиви та інші дані, використовуючи Core Data, це не так складно, як кажуть. Просто почніть з малого.

Оновлення. Крім того, якщо ви додасте підтримку Apple Watch, є ще один потенційний розгляд. NSUserDefaults вашої програми тепер автоматично надсилається до розширення для перегляду.

Використання основних даних

Тому я проігнорував попередження про те, що основні дані є більш складним рішенням, і почав читати. Протягом трьох годин я працював. У мене було збережено масив таблиць у Core Data та перезавантажити дані після відкриття програми резервного копіювання! Код підручника був досить легким для адаптації, і я зміг змусити його зберігати масиви заголовків та деталей лише з невеликим додатковим експериментом.

Тож для тих, хто читає цю публікацію, хто бореться з проблемами типу NSUserDefault або чия потреба перевищує збереження рядків, подумайте про те, щоб витратити годину-дві, граючи з основними даними.

Ось підручник, який я прочитав:

http://www.raywenderlich.com/85578/first-core-data-app-using-swift

Якщо ви не встановили прапорець "Основні дані"

Якщо ви не встановили прапорець "Основні дані" під час створення додатка, його можна додати після цього, і це займе лише п'ять хвилин:

http://craig24.com/2014/12/how-to-add-core-data-to-an-existing-swift-project-in-xcode/

http://blog.zeityer.com/post/119012600864/adding-core-data-to-an-existing-swift-project

Як видалити зі списків основних даних

Видалити дані з Coredata Swift


6
Існує середина збереження ваших даних у файлі .plist десь у каталозі Документи або в іншому місці в пісочному файлі програми.
Nicolas Miari

Я новачок, тож прийміть це питання із зерном солі, але це середина? NSUserDefaults - це практично файл p.list у будь-якому випадку, тому (виходячи з того, що я прочитав) збереження у файлі p.list у каталозі документів є таким самим, як використання NSUserDefaults. Причиною того, що я не користувався цим методом, було те, що для збереження масиву до p.list звучало так, що він передбачає додаткові кроки, як перетворення його в інший тип, а потім пізніше, при відновленні значень, потрібно повторно призначити значення після їх читання. з p.list. Знову ж таки, виключно на основі мого читання за останні кілька днів.
Дейв Г

Що ж, збереження масиву до .plist-файлів досить просто (усі об'єкти в ієрархії - це масиви, рядки, словники чи номери (немає спеціальних класів).
Nicolas Miari

Погоджено, читання файлу - це майже нічого, але ви можете розділити свої дані на окремі файли залежно від його структури. І CoreData мав значну криву навчання, принаймні востаннє, коли я перевіряв.
Nicolas Miari

3
Я б сказав: використовуйте NSUserDefaults для зберігання налаштувань (саме це означає зрештою назва), брелок для зберігання стійких та / або конфіденційних даних, спеціальна схема файлів .plist для дуже основних даних, створених додатком, і CoreData для більш важких речей .
Nicolas Miari

11

Окей, завдяки @bploat та посиланням на http://www.codingexplorer.com/nsuserdefaults-a-swift-introduction/

Я виявив, що відповідь досить проста для деякого базового зберігання рядків.

let defaults = NSUserDefaults.standardUserDefaults()

// Store
defaults.setObject("theGreatestName", forKey: "username")

// Receive
if let name = defaults.stringForKey("username")
{
    print(name)
    // Will output "theGreatestName"
}

Я підсумував це тут http://ridewing.se/blog/save-local-data-in-swift/


9

Використання NSCoding та NSKeyedArchiver - це ще один чудовий варіант для даних, надто складних для NSUserDefaults, але для яких CoreData буде надмірним. Це також дає можливість більш чітко керувати структурою файлів, що чудово, якщо ви хочете використовувати шифрування.


7

Для Swift 4.0 це стало простіше:

let defaults = UserDefaults.standard
//Set
defaults.set(passwordTextField.text, forKey: "Password")
//Get
let myPassword = defaults.string(forKey: "Password")

6

Swift 3.0

Установник: локальне зберігання

let authtoken = "12345"
    // Userdefaults helps to store session data locally 
 let defaults = UserDefaults.standard                                           
defaults.set(authtoken, forKey: "authtoken")

 defaults.synchronize()

Getter: Місцеве зберігання

 if UserDefaults.standard.string(forKey: "authtoken") != nil {

//perform your task on success }

2
Ви не повинні зберігати smth, як authtoken в UserDefaults. Будь ласка, використовуйте для цього брелок
BilalReffas

5

Для Swift 3

UserDefaults.standard.setValue(token, forKey: "user_auth_token")
print("\(UserDefaults.standard.value(forKey: "user_auth_token")!)")

Не використовуйте методи KVC для збереження даних.
rmaddy

4

Для тих, хто не захоче обробляти UserDefaults з якихось причин, є інший варіант - NSKeyedArchiver & NSKeyedUnarchiver. Це допомагає зберігати об’єкти у файл за допомогою архіватора та завантажувати заархівований файл у вихідні об’єкти.

// To archive object,
let mutableData: NSMutableData = NSMutableData()
let archiver: NSKeyedArchiver = NSKeyedArchiver(forWritingWith: mutableData)
archiver.encode(object, forKey: key)
archiver.finishEncoding()
return mutableData.write(toFile: path, atomically: true)

// To unarchive objects,
if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
    let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
    let object = unarchiver.decodeObject(forKey: key)
}

Я написав просту утиліту для збереження / завантаження об'єктів у локальному сховищі, використовував зразки вищезгаданих кодів. Ви можете побачити це. https://github.com/DragonCherry/LocalStorage


4

Швидкий 5+

Жодна з відповідей насправді детально не охоплює стандартні можливості зберігання за замовчуванням. Це може зробити набагато більше, ніж просто рядки.

У документації щодо яблук є наступні параметри для отримання "даних" за замовчуванням.

func object(forKey: String) -> Any?
//Returns the object associated with the specified key.

func url(forKey: String) -> URL?
//Returns the URL associated with the specified key.

func array(forKey: String) -> [Any]?
//Returns the array associated with the specified key.

func dictionary(forKey: String) -> [String : Any]?
//Returns the dictionary object associated with the specified key.

func string(forKey: String) -> String?
//Returns the string associated with the specified key.

func stringArray(forKey: String) -> [String]?
//Returns the array of strings associated with the specified key.

func data(forKey: String) -> Data?
//Returns the data object associated with the specified key.

func bool(forKey: String) -> Bool
//Returns the Boolean value associated with the specified key.

func integer(forKey: String) -> Int
//Returns the integer value associated with the specified key.

func float(forKey: String) -> Float
//Returns the float value associated with the specified key.

func double(forKey: String) -> Double
//Returns the double value associated with the specified key.

func dictionaryRepresentation() -> [String : Any]
//Returns a dictionary that contains a union of all key-value pairs in the domains in the search list.

Ось варіанти "налаштування"

func set(Any?, forKey: String)
//Sets the value of the specified default key.

func set(Float, forKey: String)
//Sets the value of the specified default key to the specified float value.

func set(Double, forKey: String)
//Sets the value of the specified default key to the double value.

func set(Int, forKey: String)
//Sets the value of the specified default key to the specified integer value.

func set(Bool, forKey: String)
//Sets the value of the specified default key to the specified Boolean value.

func set(URL?, forKey: String)
//Sets the value of the specified default key to the specified URL.

Якщо ви зберігаєте такі речі, як налаштування, а не великий набір даних, це цілком чудові варіанти.

Подвійний приклад :

Налаштування:

let defaults = UserDefaults.standard
var someDouble:Double = 0.5
defaults.set(someDouble, forKey: "someDouble")

Отримання:

let defaults = UserDefaults.standard
var someDouble:Double = 0.0
someDouble = defaults.double(forKey: "someDouble")

Що цікаво для одного з Getters, це DictionaryRepresentation , цей зручний інструмент візьме всі ваші типи даних незалежно від того, що вони є, і помістить їх у приємний словник, до якого ви можете отримати доступ за своїм ім'ям рядка та вказати правильний відповідний тип даних, коли ви запитаєте він повертається назад, оскільки має тип "будь-який" .

Ви також можете зберігати свої власні класи та об’єкти, використовуючи, відповідно, func set(Any?, forKey: String)і func object(forKey: String) -> Any?setter, і getter.

Сподіваємось, це ще більше пояснює потужність класу UserDefaults для зберігання локальних даних.

На замітку про те, скільки ви повинні зберігати і як часто, Hardy_Germany дав хорошу відповідь на це у цій публікації , ось цитата з нього

Як уже згадувалося багато людей: я не знаю жодного обмеження SIZE (крім фізичної пам'яті) для зберігання даних у .plist (наприклад, UserDefaults). Тож це не питання СКІЛЬКО.

Справжнє запитання повинно бути ЯК ВЗАГАЛЬНО ви пишете нові / змінені значення ... І це пов’язано зі спорядженням акумулятора, яке це запит спричинить.

IOS не має шансів уникнути фізичного запису на "диск", якщо змінено одне значення, просто щоб зберегти цілісність даних. Що стосується UserDefaults, це спричиняє весь файл, записаний на диск.

Це дозволяє активувати "диск" і тримати його живлення довше, а також запобігає переходу IOS на стан низької потужності.

Щось ще слід зазначити, як згадував користувач Mohammad Reza Farahani з цієї публікації, - це асинхронний та синхронний характер userDefaults.

Коли ви встановлюєте значення за замовчуванням, воно змінюється синхронно в межах вашого процесу та асинхронно для постійного зберігання та інших процесів.

Наприклад, якщо ви зберігаєте та швидко закриваєте програму, ви можете помітити, що вона не зберігає результати, це тому, що вона зберігається асинхронно. Ви, можливо, не помічаєте цього весь час, тому якщо ви плануєте економити перед тим, як вийти з програми, можливо, ви захочете це врахувати, надавши їй деякий час для завершення.

Можливо, у когось є приємні рішення для цього, якими вони можуть поділитися в коментарях?


0

NsUserDefaults зберігає лише невеликі змінні розміри. Якщо ви хочете зберегти багато об'єктів, ви можете використовувати CoreData як нативне рішення, або я створив бібліотеку, яка допоможе вам зберегти об'єкти так само просто, як функцію .save (). Він заснований на SQLite.

SundeedQLite

Перевірте це та скажіть мені свої коментарі

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.