วิธีบันทึกข้อมูลในเครื่องในแอพ Swift


148

ขณะนี้ฉันกำลังทำงานกับแอพ iOS ที่พัฒนาใน Swift และฉันต้องการจัดเก็บเนื้อหาที่ผู้ใช้สร้างขึ้นบนอุปกรณ์ แต่ดูเหมือนว่าฉันไม่สามารถหาวิธีที่ง่ายและรวดเร็วในการจัดเก็บ / รับเนื้อหาผู้ใช้บนอุปกรณ์

มีใครช่วยอธิบายวิธีจัดเก็บและเข้าถึงที่จัดเก็บในตัวเครื่องได้บ้าง

แนวคิดคือการจัดเก็บข้อมูลเมื่อผู้ใช้ดำเนินการกระทำและรับมันเมื่อแอปเริ่มต้น


สวัสดีและยินดีต้อนรับคุณจัดเก็บข้อมูลประเภทใด คุณสามารถให้รหัสใด ๆ เพื่อเป็นตัวอย่างของสิ่งที่คุณกำลังมองหาได้หรือไม่? ขอบคุณ
Wez

1
ข้อมูลที่ฉันต้องการจัดเก็บนั้นเป็นเพียงข้อมูลสตริง ดังนั้นเพื่อให้ง่ายจริง ๆ ฉันต้องบันทึกค่าสตริงสองค่าที่ฉันสามารถรับได้หากผู้ใช้รีสตาร์ทแอป
Nicklas Ridewing

2
คุณสามารถใช้ NSUserDefaults นี่คือข้อมูลที่คุณต้องการ codingexplorer.com/nsuserdefaults-a-swift-introduction
bpolat

คำตอบ:


197

ทางออกที่ง่ายที่สุดถ้าคุณเป็นเพียงการจัดเก็บสองสายคือNSUserDefaultsในสวิฟท์ 3 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
}

Swift 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
}

สำหรับสิ่งที่ร้ายแรงกว่าการกำหนดค่าเล็กน้อยแฟล็กหรือสตริงพื้นฐานคุณควรใช้ร้านค้าแบบถาวร - ตัวเลือกยอดนิยมในขณะนี้คืออาณาจักรแต่คุณยังสามารถใช้SQLiteหรือแอปเปิ้ลCoreDataของตัวเองได้


7
ตัวอย่างที่ดี นี่น่าจะเป็น enum แทนที่จะเป็น struct
แพนและสแกน

3
นั่นคือการดำเนินการที่แปลกประหลาดของ enum หากคุณมีค่าคงที่แบบคงที่มันอาจจะเป็นโครงสร้าง
Craig Grummitt

1
รหัสนี้ผิด อย่าใช้วิธี KVC setValue(_:forKey:)เพื่อบันทึกข้อมูลไปยัง UserDefaults ใช้UserDefaultsวิธีการที่ให้มาของset(_:forKey:)(ใน Swift 3)
rmaddy

ฉันอัพเดตรหัส Swift 3 ฉันไม่ทราบว่าไวยากรณ์ของ Swift 2 ควรเป็นอย่างไร
rmaddy

@ rmaddy มันก็ดีเหมือนเดิม
Wez

57

พวกเขาบอกว่าใช้ NSUserDefaults

เมื่อฉันใช้การจัดเก็บข้อมูลระยะยาว (หลังจากปิดแอพ) เป็นครั้งแรกทุกอย่างที่ฉันอ่านออนไลน์ชี้ไปที่ NSUserDefaults อย่างไรก็ตามฉันต้องการเก็บพจนานุกรมและแม้ว่าเป็นไปได้มันก็พิสูจน์แล้วว่าเป็นความเจ็บปวด ฉันใช้เวลาหลายชั่วโมงเพื่อที่จะได้รับข้อผิดพลาดในการพิมพ์หายไป

NSUserDefaults มี จำกัด ในฟังก์ชั่น

การอ่านเพิ่มเติมเปิดเผยว่าการอ่าน / เขียนของ NSUserDefaults บังคับให้แอปอ่าน / เขียนทุกอย่างหรืออะไรเลยในเวลาเดียวกันดังนั้นมันจึงไม่มีประสิทธิภาพ จากนั้นฉันได้เรียนรู้ว่าการเรียกใช้อาเรย์นั้นไม่ได้อยู่ตรงหน้า ฉันรู้ว่าถ้าคุณเก็บมากกว่าสองสามสายหรือบูลีน NSUserDefaults จริงๆไม่เหมาะ

มันยังไม่สามารถปรับขนาดได้ หากคุณเรียนรู้วิธีเขียนโค้ดเรียนรู้วิธีปรับขนาดได้ ใช้ NSUserDefaults สำหรับการจัดเก็บสตริงแบบธรรมดาหรือบูลีนที่เกี่ยวข้องกับการกำหนดค่าตามความชอบเท่านั้น จัดเก็บอาร์เรย์และข้อมูลอื่น ๆ โดยใช้ Core Data ไม่ใช่เรื่องยากอย่างที่พวกเขาพูด เพิ่งเริ่มต้นเล็ก ๆ

อัปเดต: นอกจากนี้หากคุณเพิ่มการสนับสนุน Apple Watch จะมีข้อควรพิจารณาอีกประการหนึ่ง NSUserDefaults ของแอปของคุณจะถูกส่งไปยังส่วนขยายการดูโดยอัตโนมัติ

การใช้ข้อมูลหลัก

ดังนั้นฉันจึงไม่สนใจคำเตือนเกี่ยวกับ Core Data ซึ่งเป็นวิธีแก้ปัญหาที่ยากขึ้นและเริ่มอ่าน ภายในสามชั่วโมงฉันได้ทำงาน ฉันได้บันทึกอาร์เรย์ตารางของฉันใน 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 บางแห่งในไดเรกทอรีเอกสารหรือที่อื่น ๆ ในไดเรกทอรี sandboxed ของแอป
Nicolas Miari

ฉันเป็นสามเณรลองถามคำถามนี้ด้วยเกลือเม็ดหนึ่ง แต่พื้นกลางนั่นหรือไม่ NSUserDefaults เป็นไฟล์ p.list ในทางปฏิบัติดังนั้นการบันทึกไปยังไฟล์ p.list ในไดเรกทอรีเอกสารนั้นเป็นแบบเดียวกับการใช้ NSUserDefaults เหตุผลที่ฉันไม่ได้ใช้วิธีการนั้นเนื่องจากการบันทึกอาร์เรย์ไปยัง p.list ฟังดูเหมือนว่ามันเกี่ยวข้องกับขั้นตอนพิเศษเช่นการแปลงเป็นประเภทอื่นแล้วต่อมาเมื่อคืนค่ามันต้องกำหนดค่าใหม่หลังจากอ่าน จาก p.list อีกครั้งขึ้นอยู่กับการอ่านของฉันในช่วงไม่กี่วันที่ผ่านมา
เดฟ G

การบันทึกอาร์เรย์เป็นไฟล์. plist นั้นค่อนข้างตรงไปตรงมา (วัตถุทั้งหมดในลำดับชั้นคืออาร์เรย์, สตริง, พจนานุกรมหรือตัวเลข (ไม่มีคลาสที่กำหนดเอง)
Nicolas Miari

เห็นด้วยว่าการอ่านไฟล์นั้นไม่มีค่าอะไรเลย แต่คุณสามารถแบ่งข้อมูลของคุณออกเป็นไฟล์ต่าง ๆ ได้ขึ้นอยู่กับโครงสร้างของไฟล์ และ CoreData มีช่วงการเรียนรู้ที่สำคัญอย่างน้อยที่สุดฉันก็ตรวจสอบครั้งล่าสุด
Nicolas Miari

3
ผมจะบอกว่าใช้งาน: ใช้ NSUserDefaults การตั้งค่าการจัดเก็บ (ว่าสิ่งที่ชื่อหมายถึงหลังจากทั้งหมด), พวงกุญแจในการเก็บข้อมูลถาวรและ / หรือมีความสำคัญโครงการที่กำหนดเองของไฟล์ .plist สำหรับขั้นพื้นฐานมากข้อมูลแอปสร้างและ CoreData สำหรับสิ่งที่หนักมากขึ้น .
Nicolas Miari

11

ขอบคุณมากกับ@bploatและลิงก์ไปยังhttp://www.codingexplorer.com/

ฉันพบว่าคำตอบนั้นง่ายสำหรับการจัดเก็บสตริงพื้นฐาน

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 ใดที่จะ overkill นอกจากนี้ยังเปิดโอกาสให้คุณจัดการโครงสร้างไฟล์ได้ชัดเจนยิ่งขึ้นซึ่งดีมากหากคุณต้องการใช้การเข้ารหัส


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

Setter: Local Storage

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 .. โปรดใช้ Keychain เพื่อสิ่งนี้
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 ช่วยบันทึกวัตถุลงในไฟล์โดยใช้ Archiver และโหลดไฟล์ที่เก็บถาวรไปยังวัตถุต้นฉบับ

// 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

Swift 5+

ไม่มีคำตอบใดที่ครอบคลุมรายละเอียดเกี่ยวกับความสามารถในการจัดเก็บในตัวเครื่อง มันสามารถทำได้มากกว่าแค่สายอักขระ

คุณมีตัวเลือกต่อไปนี้โดยตรงจากเอกสารของ Apple สำหรับการ 'รับ' ข้อมูลจากค่าเริ่มต้น

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 , getter ที่มีประโยชน์นี้จะนำข้อมูลทุกชนิดของคุณไปใช้โดยไม่คำนึงว่ามันคืออะไรและใส่ไว้ในพจนานุกรมที่ดีที่คุณสามารถเข้าถึงได้โดยชื่อสตริงและให้ประเภทข้อมูลที่ถูกต้อง มันกลับมาเนื่องจากเป็นประเภท'ใด ๆ'

คุณสามารถจัดเก็บคลาสและวัตถุของคุณเองโดยใช้func set(Any?, forKey: String)และfunc object(forKey: String) -> Any?setter และทะเยอทะยานตามลำดับ

หวังว่านี่จะช่วยเพิ่มประสิทธิภาพของคลาส UserDefaults ให้มากขึ้นสำหรับการจัดเก็บข้อมูลในเครื่อง

เมื่อทราบเท่าไหร่ที่คุณควรเก็บและความถี่ที่Hardy_Germanyให้คำตอบที่ดีในการที่เกี่ยวกับเรื่องนี้โพสต์ที่นี่เป็นคำพูดจากมัน

ดังที่ได้กล่าวไปแล้ว: ฉันไม่ได้ตระหนักถึงข้อ จำกัด ขนาดใด ๆ (ยกเว้นหน่วยความจำกายภาพ) เพื่อจัดเก็บข้อมูลใน. plist (เช่น UserDefaults) ดังนั้นจึงไม่ใช่คำถามของวิธีการมาก

คำถามที่แท้จริงควรจะเป็นอย่างไรคุณเขียนใหม่ / เปลี่ยนค่า ... และนี่คือที่เกี่ยวข้องกับแบตเตอรี่หมดการเขียนนี้จะทำให้

IOS ไม่มีโอกาสที่จะหลีกเลี่ยงการเขียนทางกายภาพไปยัง "ดิสก์" หากค่าเดียวมีการเปลี่ยนแปลงเพียงเพื่อรักษาความสมบูรณ์ของข้อมูล เกี่ยวกับ UserDefaults ทำให้ไฟล์ทั้งหมดถูกเขียนใหม่ในดิสก์

สิ่งนี้จะเพิ่มพลังให้กับ "ดิสก์" และทำให้มันใช้พลังงานได้นานขึ้นและป้องกันไม่ให้ IOS ไปสู่สถานะพลังงานต่ำ

อย่างอื่นที่จะต้องทราบดังกล่าวโดยใช้โมฮัมหมัดเรซา Farahani จากนี้โพสต์เป็นตรงกันและซิงโครธรรมชาติของ userDefaults

เมื่อคุณตั้งค่าเริ่มต้นจะมีการเปลี่ยนแปลงพร้อมกันภายในกระบวนการของคุณและแบบอะซิงโครนัสกับที่เก็บข้อมูลถาวรและกระบวนการอื่น ๆ

ตัวอย่างเช่นถ้าคุณบันทึกและปิดโปรแกรมอย่างรวดเร็วคุณอาจสังเกตเห็นว่าไม่ได้บันทึกผลลัพธ์นี่เป็นเพราะโปรแกรมยังคงทำงานแบบอะซิงโครนัส คุณอาจไม่ได้สังเกตเรื่องนี้ตลอดเวลาดังนั้นหากคุณวางแผนที่จะบันทึกก่อนที่จะออกจากโปรแกรมคุณอาจต้องการบัญชีสำหรับสิ่งนี้โดยให้เวลาพอที่จะเสร็จสิ้น

บางทีใครบางคนอาจมีทางออกที่ดีสำหรับสิ่งนี้ที่พวกเขาสามารถแบ่งปันในความคิดเห็นได้?


0

NsUserDefaults บันทึกเฉพาะตัวแปรขนาดเล็ก หากคุณต้องการบันทึกวัตถุจำนวนมากคุณสามารถใช้ CoreData เป็นวิธีแก้ปัญหาแบบเนทีฟหรือฉันสร้างไลบรารีที่ช่วยให้คุณบันทึกวัตถุได้ง่ายเหมือนฟังก์ชั่น. save () มันขึ้นอยู่กับ SQLite

SundeedQLite

ตรวจสอบและบอกความคิดเห็นของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.