Swifty และ Modern UserDefaults
จัดเก็บคู่คีย์-ค่าอย่างต่อเนื่องในการเปิดตัวแอปของคุณ
มันใช้ UserDefaults ที่อยู่ด้านล่าง แต่เปิดเผยด้านหน้าที่ปลอดภัยประเภทด้วยสิ่งอำนวยความสะดวกที่ดีมากมาย
มันใช้ในการผลิตโดยแอพทั้งหมดของฉัน (ผู้ใช้ 4 ล้านคน)
UserDefaults เปลี่ยนไป@AppStorageCodableToggle Swiftui ที่สะดวกสบาย เพิ่ม https://github.com/sindresorhus/Defaults ในแท็บ“ Swift Package Manager” ใน Xcode
Int(8/16/32/64)UInt(8/16/32/64)DoubleCGFloatFloatStringBoolDateDataURLUUIDRangeClosedRangeCodableNSSecureCodingColor 1 (Swiftui)Color.Resolved 1 (Swiftui)NSColorUIColorNSFontDescriptorUIFontDescriptor ค่าเริ่มต้นยังรองรับประเภทข้างต้นที่ห่อหุ้มด้วย Array Set Dictionary Range ClosedRange และแม้กระทั่งห่อเป็นประเภทซ้อนกัน ตัวอย่างเช่น [[String: Set<[String: Int]>]]
สำหรับประเภทอื่น ๆ ดูตัวอย่าง enum, ตัวอย่าง Codable หรือการใช้งานขั้นสูง สำหรับตัวอย่างเพิ่มเติมดูการทดสอบ/defaultstests
คุณสามารถเพิ่มการสนับสนุนสำหรับประเภทที่กำหนดเองได้อย่างง่ายดาย
หากประเภทที่สอดคล้องกับทั้ง NSSecureCoding และ Codable Codable จะใช้สำหรับการทำให้เป็นอนุกรม
เอกสาร API
คุณประกาศคีย์ค่าเริ่มต้นล่วงหน้าด้วยค่าและค่าเริ่มต้น
ชื่อคีย์ต้องเป็น ASCII ไม่เริ่มต้นด้วย @ และไม่สามารถมีจุด ( . )
import Defaults
extension Defaults . Keys {
static let quality = Key < Double > ( " quality " , default : 0.8 )
// ^ ^ ^ ^
// Key Type UserDefaults name Default value
} จากนั้นคุณสามารถเข้าถึงเป็นตัวห้อยบน Defaults Globals:
Defaults [ . quality ]
//=> 0.8
Defaults [ . quality ] = 0.5
//=> 0.5
Defaults [ . quality ] += 0.1
//=> 0.6
Defaults [ . quality ] = " ? "
//=> [Cannot assign value of type 'String' to type 'Double']นอกจากนี้คุณยังสามารถประกาศคีย์เสริมสำหรับเมื่อคุณไม่ต้องการประกาศค่าเริ่มต้นล่วงหน้า:
extension Defaults . Keys {
static let name = Key < Double ? > ( " name " )
}
if let name = Defaults [ . name ] {
print ( name )
} ค่าเริ่มต้นจะ nil
คุณยังสามารถระบุค่าเริ่มต้นแบบไดนามิก สิ่งนี้จะมีประโยชน์เมื่อค่าเริ่มต้นอาจเปลี่ยนแปลงในช่วงอายุการใช้งานของแอพ:
extension Defaults . Keys {
static let camera = Key < AVCaptureDevice ? > ( " camera " ) { . default ( for : . video ) }
} enum DurationKeys : String , Defaults . Serializable {
case tenMinutes = " 10 Minutes "
case halfHour = " 30 Minutes "
case oneHour = " 1 Hour "
}
extension Defaults . Keys {
static let defaultDuration = Key < DurationKeys > ( " defaultDuration " , default : . oneHour )
}
Defaults [ . defaultDuration ] . rawValue
//=> "1 Hour"(ใช้งานได้ตราบเท่าที่ค่าดิบของ enum เป็นประเภทใด ๆ ที่รองรับ)
struct User : Codable , Defaults . Serializable {
let name : String
let age : String
}
extension Defaults . Keys {
static let user = Key < User > ( " user " , default : . init ( name : " Hello " , age : " 24 " ) )
}
Defaults [ . user ] . name
//=> "Hello" คุณไม่จำเป็นต้องแนบปุ่มเข้ากับ Defaults.Keys
let isUnicorn = Defaults . Key < Bool > ( " isUnicorn " , default : true )
Defaults [ isUnicorn ]
//=> true@Default ใน View คุณสามารถใช้ wrapper คุณสมบัติ @Default เพื่อรับ/ตั้งค่ารายการ Defaults และยังมีการอัปเดตมุมมองเมื่อค่าเปลี่ยน สิ่งนี้คล้ายกับ @State
extension Defaults . Keys {
static let hasUnicorn = Key < Bool > ( " hasUnicorn " , default : false )
}
struct ContentView : View {
@ Default ( . hasUnicorn ) var hasUnicorn
var body : some View {
Text ( " Has Unicorn: ( hasUnicorn ) " )
Toggle ( " Toggle " , isOn : $hasUnicorn )
Button ( " Reset " ) {
_hasUnicorn . reset ( )
}
}
} โปรดทราบว่ามันคือ @Default ไม่ใช่ @Defaults
คุณไม่สามารถใช้ @Default ใน ObservableObject มันหมายถึงการใช้ใน View
@ObservableDefault ใน @Observable ด้วย macro @ObservableDefault คุณสามารถใช้ Defaults ภายในคลาส @Observable ที่ใช้กรอบการสังเกต การทำเช่นนั้นเป็นเรื่องง่ายเหมือนการนำเข้า DefaultsMacros และเพิ่มสองบรรทัดลงในคุณสมบัติ (โปรดทราบว่าจำเป็นต้องมี @ObservationIgnored เพื่อป้องกันการปะทะด้วย @Observable ):
สำคัญ
เวลาสร้างจะเพิ่มขึ้นเมื่อใช้มาโคร
แมโครที่ swift-syntax ซึ่งหมายความว่าเมื่อคุณรวบรวมรหัสที่มีมาโครเป็นการพึ่งพาคุณต้องรวบรวม swift-syntax ด้วย เป็นที่ทราบกันดีว่าการทำเช่นนั้นมีผลกระทบอย่างรุนแรงในเวลาสร้างและในขณะที่มันเป็นปัญหาที่กำลังติดตาม (ดู swift-syntax #2421) ปัจจุบันยังไม่มีวิธีแก้ปัญหา
import Defaults
import DefaultsMacros
@ Observable
final class UnicornManager {
@ ObservableDefault ( . hasUnicorn )
@ ObservationIgnored
var hasUnicorn : Bool
} Toggle นอกจากนี้ยังมี wrapper SwiftUI.Toggle ที่ทำให้ง่ายต่อการสร้างสลับตามคีย์ค่า Defaults ที่มีค่า Bool
extension Defaults . Keys {
static let showAllDayEvents = Key < Bool > ( " showAllDayEvents " , default : false )
}
struct ShowAllDayEventsSetting : View {
var body : some View {
Defaults . Toggle ( " Show All-Day Events " , key : . showAllDayEvents )
}
}คุณยังสามารถฟังการเปลี่ยนแปลง:
struct ShowAllDayEventsSetting : View {
var body : some View {
Defaults . Toggle ( " Show All-Day Events " , key : . showAllDayEvents )
// Note that this has to be directly attached to `Defaults.Toggle`. It's not `View#onChange()`.
. onChange {
print ( " Value " , $0 )
}
}
} extension Defaults . Keys {
static let isUnicornMode = Key < Bool > ( " isUnicornMode " , default : false )
}
// …
Task {
for await value in Defaults . updates ( . isUnicornMode ) {
print ( " Value: " , value )
}
} ตรงกันข้ามกับการสังเกตคีย์ UserDefaults ดั้งเดิมที่นี่คุณจะได้รับวัตถุการเปลี่ยนแปลงที่พิมพ์ลงอย่างมาก
extension Defaults . Keys {
static let isUnicornMode = Key < Bool > ( " isUnicornMode " , default : false )
}
Defaults [ . isUnicornMode ] = true
//=> true
Defaults . reset ( . isUnicornMode )
Defaults [ . isUnicornMode ]
//=> false สิ่งนี้ใช้งานได้กับ Key ที่มีตัวเลือกด้วยซึ่งจะถูกรีเซ็ตกลับเป็น nil
การเปลี่ยนแปลงที่เกิดขึ้นภายใน Defaults.withoutPropagation ปิดการจัดเรียงจะไม่ถูกเผยแพร่ไปยังการโทรกลับ ( Defaults.observe() หรือ Defaults.publisher() ) และสามารถป้องกันการเรียกซ้ำที่ไม่มีที่สิ้นสุด
let observer = Defaults . observe ( keys : . key1 , . key2 ) {
// …
Defaults . withoutPropagation {
// Update `.key1` without propagating the change to listeners.
Defaults [ . key1 ] = 11
}
// This will be propagated.
Defaults [ . someKey ] = true
}UserDefaults มีน้ำตาลใช้งานได้เช่นกัน:
extension Defaults . Keys {
static let isUnicorn = Key < Bool > ( " isUnicorn " , default : true )
}
UserDefaults . standard [ . isUnicorn ]
//=> trueUserDefaults ใช้ร่วมกัน let extensionDefaults = UserDefaults ( suiteName : " com.unicorn.app " ) !
extension Defaults . Keys {
static let isUnicorn = Key < Bool > ( " isUnicorn " , default : true , suite : extensionDefaults )
}
Defaults [ . isUnicorn ]
//=> true
// Or
extensionDefaults [ . isUnicorn ]
//=> trueUserDefaults เมื่อคุณสร้างค่า Defaults.Key จะลงทะเบียนค่า default โดยอัตโนมัติด้วย UserDefaults ปกติ ซึ่งหมายความว่าคุณสามารถใช้ประโยชน์จากค่าเริ่มต้นเช่นการผูกในตัวสร้างอินเตอร์เฟส
extension Defaults . Keys {
static let isUnicornMode = Key < Bool > ( " isUnicornMode " , default : true )
}
print ( UserDefaults . standard . bool ( forKey : Defaults . Keys . isUnicornMode . name ) )
//=> trueหมายเหตุ ค่า
Defaults.Keyที่มีค่าเริ่มต้นแบบไดนามิกจะไม่ลงทะเบียนค่าเริ่มต้นในUserDefaults
DefaultsDefaults.Keys ประเภท: class
เก็บกุญแจ
Defaults.Key (นามแฝง Defaults.Keys.Key ) Defaults . Key < T > ( _ name : String , default : T , suite : UserDefaults = . standard ) ประเภท: class
สร้างคีย์ที่มีค่าเริ่มต้น
ค่าเริ่มต้นจะถูกเขียนไปยัง UserDefaults จริงและสามารถใช้งานได้ที่อื่น ตัวอย่างเช่นด้วยการเชื่อมต่อการสร้างอินเตอร์เฟส
Defaults.Serializable public protocol DefaultsSerializable {
typealias Value = Bridge . Value
typealias Serializable = Bridge . Serializable
associatedtype Bridge : Defaults . Bridge
static var bridge : Bridge { get }
} ประเภท: protocol
ประเภทที่สอดคล้องกับโปรโตคอลนี้สามารถใช้กับ Defaults
ประเภทควรมี bridge ตัวแปรคงที่ซึ่งควรอ้างอิงอินสแตนซ์ของประเภทที่สอดคล้องกับ Defaults.Bridge
Defaults.Bridge public protocol DefaultsBridge {
associatedtype Value
associatedtype Serializable
func serialize ( _ value : Value ? ) -> Serializable ?
func deserialize ( _ object : Serializable ? ) -> Value ?
} ประเภท: protocol
Bridge มีหน้าที่รับผิดชอบในการทำให้เป็นอนุกรมและการลดลง
มันมีสอง Value ที่เกี่ยวข้องและ Serializable
Value : ประเภทที่คุณต้องการใช้Serializable : ประเภทที่เก็บไว้ใน UserDefaultsserialize : ดำเนินการก่อนที่จะจัดเก็บลงใน UserDefaultsdeserialize : ดำเนินการหลังจากดึงค่าจาก UserDefaults Defaults.AnySerializable Defaults . AnySerializable < Value : Defaults . Serializable > ( _ value : Value ) ประเภท: class
wrapper ที่ติดตั้งแบบพิมพ์สำหรับค่า Defaults.Serializable
get<Value: Defaults.Serializable>() -> Value? : ดึงค่าประเภทที่เป็น Value จาก UserDefaultsget<Value: Defaults.Serializable>(_: Value.Type) -> Value? : ระบุ Value ที่คุณต้องการเรียกคืน สิ่งนี้มีประโยชน์ในบางกรณีที่คลุมเครือset<Value: Defaults.Serializable>(_ newValue: Value) : ตั้งค่าใหม่สำหรับ Defaults.AnySerializable Defaults.reset(keys…) ประเภท: func
รีเซ็ตปุ่มที่กำหนดกลับเป็นค่าเริ่มต้น
นอกจากนี้คุณยังสามารถระบุคีย์สตริงซึ่งจะมีประโยชน์หากคุณต้องการจัดเก็บคีย์บางส่วนในคอลเลกชันเนื่องจากไม่สามารถเก็บ Defaults.Key ในคอลเล็กชันเพราะมันเป็นเรื่องทั่วไป
Defaults.removeAll Defaults . removeAll ( suite : UserDefaults = . standard ) ประเภท: func
ลบรายการทั้งหมดออกจากชุด UserDefaults ที่กำหนด
Defaults.withoutPropagation(_ closure:)ดำเนินการปิดโดยไม่เรียกเหตุการณ์การเปลี่ยนแปลง
การเปลี่ยนแปลงคีย์ค่า Defaults ใด ๆ ที่เกิดขึ้นภายในการปิดจะไม่เผยแพร่ไปยังผู้ฟังเหตุการณ์ค่า Defaults ( Defaults.observe() และ Defaults.publisher() ) สิ่งนี้มีประโยชน์ในการป้องกันการเรียกซ้ำที่ไม่มีที่สิ้นสุดเมื่อคุณต้องการเปลี่ยนคีย์ในการเรียกกลับการเปลี่ยนแปลงสำหรับการเปลี่ยนแปลงสำหรับคีย์เดียวกัน
@Default(_ key:) รับ/ตั้งค่ารายการ Defaults และให้มุมมอง Swiftui ได้รับการอัปเดตเมื่อค่าเปลี่ยน
Defaults.CollectionSerializable public protocol DefaultsCollectionSerializable : Collection , Defaults . Serializable {
init ( _ elements : [ Element ] )
} ประเภท: protocol
Collection ที่สามารถเก็บไว้ใน UserDefaults ดั้งเดิม
ควรมี initializer init(_ elements: [Element]) เพื่อให้ Defaults ทำ de-serialization
Defaults.SetAlgebraSerializable public protocol DefaultsSetAlgebraSerializable : SetAlgebra , Defaults . Serializable {
func toArray ( ) -> [ Element ]
} ประเภท: protocol
SetAlgebra ที่สามารถเก็บไว้ใน UserDefaults ดั้งเดิม
มันควรจะมีฟังก์ชั่น func toArray() -> [Element] เพื่อให้ Defaults ทำอนุกรม
แม้ว่า Defaults ต้นจะมีการสนับสนุนในตัวสำหรับหลายประเภท แต่คุณอาจต้องใช้ประเภทที่กำหนดเองของคุณเอง คู่มือด้านล่างจะแสดงวิธีการทำให้ประเภทของคุณเองทำงานด้วย Defaults
struct User {
let name : String
let age : String
}Defaults.Bridge ซึ่งรับผิดชอบในการจัดการกับการทำให้เป็นอนุกรมและ deserialization struct UserBridge : Defaults . Bridge {
typealias Value = User
typealias Serializable = [ String : String ]
public func serialize ( _ value : Value ? ) -> Serializable ? {
guard let value else {
return nil
}
return [
" name " : value . name ,
" age " : value . age
]
}
public func deserialize ( _ object : Serializable ? ) -> Value ? {
guard
let object ,
let name = object [ " name " ] ,
let age = object [ " age " ]
else {
return nil
}
return User (
name : name ,
age : age
)
}
}User ที่สอดคล้องกับ Defaults.Serializable สะพานคงที่ของมันควรเป็นสะพานที่เราสร้างไว้ข้างต้น struct User {
let name : String
let age : String
}
extension User : Defaults . Serializable {
static let bridge = UserBridge ( )
} extension Defaults . Keys {
static let user = Defaults . Key < User > ( " user " , default : User ( name : " Hello " , age : " 24 " ) )
static let arrayUser = Defaults . Key < [ User ] > ( " arrayUser " , default : [ User ( name : " Hello " , age : " 24 " ) ] )
static let setUser = Defaults . Key < Set < User>> ( " user " , default : Set ( [ User ( name : " Hello " , age : " 24 " ) ] ) )
static let dictionaryUser = Defaults . Key < [ String : User ] > ( " dictionaryUser " , default : [ " user " : User ( name : " Hello " , age : " 24 " ) ] )
}
Defaults [ . user ] . name //=> "Hello"
Defaults [ . arrayUser ] [ 0 ] . name //=> "Hello"
Defaults [ . setUser ] . first ? . name //=> "Hello"
Defaults [ . dictionaryUser ] [ " user " ] ? . name //=> "Hello" อาจมีสถานการณ์ที่คุณต้องการใช้ [String: Any] โดยตรง แต่ Defaults ต้องการค่าของมันเพื่อให้สอดคล้องกับ Defaults.Serializable ค่าเริ่มต้นประเภท Defaults.AnySerializable ช่วยเอาชนะข้อ จำกัด นี้
Defaults.AnySerializable ใช้ได้เฉพาะสำหรับค่าที่สอดคล้องกับ Defaults.Serializable
คำเตือน: ควรใช้ everaser ประเภทเมื่อไม่มีวิธีอื่นในการจัดการเพราะมันมีประสิทธิภาพที่แย่กว่ามาก ควรใช้ในประเภทที่ห่อหุ้มเท่านั้น ตัวอย่างเช่นห่อด้วย Array Set หรือ Dictionary
Defaults.AnySerializable ExpressibleByArrayLiteral กับ ExpressibleByStringLiteral , ExpressibleByIntegerLiteral , ExpressibleByFloatLiteral , ExpressibleByBooleanLiteral , ExpressibleByNilLiteral , ExpressibleByDictionaryLiteral
ซึ่งหมายความว่าคุณสามารถกำหนดประเภทดั้งเดิมเหล่านี้ได้โดยตรง:
let any = Defaults . Key < Defaults . AnySerializable > ( " anyKey " , default : 1 )
Defaults [ any ] = " ? " get and setสำหรับประเภทอื่น ๆ คุณจะต้องกำหนดเช่นนี้:
enum mime : String , Defaults . Serializable {
case JSON = " application/json "
case STREAM = " application/octet-stream "
}
let any = Defaults . Key < Defaults . AnySerializable > ( " anyKey " , default : [ Defaults . AnySerializable ( mime . JSON ) ] )
if let mimeType : mime = Defaults [ any ] . get ( ) {
print ( mimeType . rawValue )
//=> "application/json"
}
Defaults [ any ] . set ( mime . STREAM )
if let mimeType : mime = Defaults [ any ] . get ( ) {
print ( mimeType . rawValue )
//=> "application/octet-stream"
} Array Set หรือ Dictionary Defaults.AnySerializable ยังรองรับประเภทข้างต้นที่ห่อหุ้มใน Array , Set , Dictionary
นี่คือตัวอย่างสำหรับ [String: Defaults.AnySerializable] :
extension Defaults . Keys {
static let magic = Key < [ String : Defaults . AnySerializable ] > ( " magic " , default : [ : ] )
}
enum mime : String , Defaults . Serializable {
case JSON = " application/json "
}
// …
Defaults [ . magic ] [ " unicorn " ] = " ? "
if let value : String = Defaults [ . magic ] [ " unicorn " ] ? . get ( ) {
print ( value )
//=> "?"
}
Defaults [ . magic ] [ " number " ] = 3
Defaults [ . magic ] [ " boolean " ] = true
Defaults [ . magic ] [ " enum " ] = Defaults . AnySerializable ( mime . JSON )
if let mimeType : mime = Defaults [ . magic ] [ " enum " ] ? . get ( ) {
print ( mimeType . rawValue )
//=> "application/json"
}สำหรับตัวอย่างเพิ่มเติมดูการทดสอบ/ค่าเริ่มต้น SanyserializableTests
Codable ที่ไม่ชัดเจน คุณอาจมีประเภทที่สอดคล้องกับ Codable & NSSecureCoding หรือ enum Codable & RawRepresentable โดยค่าเริ่มต้น Defaults จะต้องการความสอดคล้อง Codable และใช้ CodableBridge เพื่อทำให้เป็นอนุกรมเป็นสตริง JSON หากคุณต้องการทำให้เป็นอนุกรมเป็นข้อมูล NSSecureCoding หรือใช้ค่าดิบของ RawRepresentable enum คุณสามารถสอดคล้องกับ Defaults.PreferNSSecureCoding หรือ Defaults.PreferRawRepresentable
enum mime : String , Codable , Defaults . Serializable , Defaults . PreferRawRepresentable {
case JSON = " application/json "
}
extension Defaults . Keys {
static let magic = Key < [ String : Defaults . AnySerializable ] > ( " magic " , default : [ : ] )
}
print ( UserDefaults . standard . string ( forKey : " magic " ) )
//=> application/json หากเราไม่ได้เพิ่ม Defaults.PreferRawRepresentable การเป็นตัวแทนที่เก็บไว้จะเป็น "application/json" แทน application/json
สิ่งนี้อาจเป็นประโยชน์หากคุณสอดคล้องกับประเภทที่คุณไม่สามารถควบคุมค่า Defaults.Serializable เนื่องจากประเภทจะได้รับการกำหนดค่าความสอดคล้อง Codable ตลอดเวลาจากนั้นการเป็นตัวแทนที่เก็บไว้จะเปลี่ยนไปซึ่งอาจทำให้ค่าไม่สามารถอ่านได้ โดยการกำหนดสะพานที่จะใช้อย่างชัดเจนคุณมั่นใจว่าการเป็นตัวแทนที่เก็บไว้จะยังคงเหมือนเดิมเสมอ
Collection ที่กำหนดเองCollection ของคุณและทำให้องค์ประกอบของมันสอดคล้องกับ Defaults.Serializable struct Bag < Element : Defaults . Serializable > : Collection {
var items : [ Element ]
var startIndex : Int { items . startIndex }
var endIndex : Int { items . endIndex }
mutating func insert ( element : Element , at : Int ) {
items . insert ( element , at : at )
}
func index ( after index : Int ) -> Int {
items . index ( after : index )
}
subscript ( position : Int ) -> Element {
items [ position ]
}
}Bag ที่สอดคล้องกับ Defaults.CollectionSerializable collectionserializable extension Bag : Defaults . CollectionSerializable {
init ( _ elements : [ Element ] ) {
self . items = elements
}
} extension Defaults . Keys {
static let stringBag = Key < Bag < String > > ( " stringBag " , default : Bag ( [ " Hello " , " World! " ] ) )
}
Defaults [ . stringBag ] [ 0 ] //=> "Hello"
Defaults [ . stringBag ] [ 1 ] //=> "World!"SetAlgebra ที่กำหนดเองSetAlgebra ของคุณและทำให้องค์ประกอบของมันสอดคล้องกับ Defaults.Serializable & Hashable struct SetBag < Element : Defaults . Serializable & Hashable > : SetAlgebra {
var store = Set < Element > ( )
init ( ) { }
init ( _ store : Set < Element > ) {
self . store = store
}
func contains ( _ member : Element ) -> Bool {
store . contains ( member )
}
func union ( _ other : SetBag ) -> SetBag {
SetBag ( store . union ( other . store ) )
}
func intersection ( _ other : SetBag ) -> SetBag {
var setBag = SetBag ( )
setBag . store = store . intersection ( other . store )
return setBag
}
func symmetricDifference ( _ other : SetBag ) -> SetBag {
var setBag = SetBag ( )
setBag . store = store . symmetricDifference ( other . store )
return setBag
}
@ discardableResult
mutating func insert ( _ newMember : Element ) -> ( inserted : Bool , memberAfterInsert : Element ) {
store . insert ( newMember )
}
mutating func remove ( _ member : Element ) -> Element ? {
store . remove ( member )
}
mutating func update ( with newMember : Element ) -> Element ? {
store . update ( with : newMember )
}
mutating func formUnion ( _ other : SetBag ) {
store . formUnion ( other . store )
}
mutating func formSymmetricDifference ( _ other : SetBag ) {
store . formSymmetricDifference ( other . store )
}
mutating func formIntersection ( _ other : SetBag ) {
store . formIntersection ( other . store )
}
}SetBag ที่สอดคล้องกับ Defaults.SetAlgebraSerializable extension SetBag : Defaults . SetAlgebraSerializable {
func toArray ( ) -> [ Element ] {
Array ( store )
}
} extension Defaults . Keys {
static let stringSet = Key < SetBag < String > > ( " stringSet " , default : SetBag ( [ " Hello " , " World! " ] ) )
}
Defaults [ . stringSet ] . contains ( " Hello " ) //=> true
Defaults [ . stringSet ] . contains ( " World! " ) //=> true หลังจาก Defaults V5 คุณไม่จำเป็นต้องใช้ Codable จัดเก็บพจนานุกรมค่า Defaults รองรับการจัดเก็บพจนานุกรมโดยธรรมชาติ สำหรับประเภทการสนับสนุน Defaults ดูประเภทการสนับสนุน
SwiftyUserDefaults อย่างไร?มันได้รับแรงบันดาลใจจากแพ็คเกจนั้นและโซลูชั่นอื่น ๆ ความแตกต่างที่สำคัญคือโมดูลนี้ไม่ได้เป็นฮาร์ดโค้ดค่าเริ่มต้นและมาพร้อมกับการรองรับการเข้ารหัส
อดีต
คุณไม่สามารถใช้ Color.accentColor ↩ 2