신속하고 현대적인 userDefaults
앱의 출시를 통해 키 값 쌍을 지속적으로 저장하십시오.
아래에 UserDefaults 사용하지만 많은 편의성을 가진 유형-안전한 외관을 노출시킵니다.
모든 앱 (4 백만+ 사용자)에서 제작에 사용됩니다.
UserDefaults 값이 변경 될 때보기를 업데이트하는 속성 래퍼.@AppStorage 에 대한 혜택Codable 더 많은 유형을 지원합니다.Toggle 구성 요소가 제공됩니다. Xcode의 "Swift Package Manager"탭에서 https://github.com/sindresorhus/Defaults 추가하십시오.
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]>]] .
더 많은 유형은 열거 예제, 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 Global의 첨자로 액세스 할 수 있습니다.
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"(이것은 열거의 원시 값이 지원되는 유형 중 하나 인 한 작동합니다)
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 @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 입니다.
ObservableObject 에서 @Default 사용할 수 없습니다. 그것은 View 에서 사용되어야합니다.
@Observable 의 @ObservableDefault @ObservableDefault 매크로를 사용하면 관찰 프레임 워크를 사용하는 @Observable 클래스 내부의 Defaults 사용할 수 있습니다. 이렇게하는 것은 DefaultsMacros 가져오고 속성에 두 줄을 추가하는 것만 큼 간단합니다 ( @Observable 과의 충돌을 방지하려면 @ObservationIgnored 추가하는 것이 필요합니다).
중요한
매크로를 사용할 때 빌드 시간이 증가합니다.
신속한 매크로는 swift-syntax 패키지에 따라 다릅니다. 즉, 매크로를 포함하는 코드를 종속성으로 컴파일하면 swift-syntax 도 컴파일해야합니다. 그렇게하는 것은 빌드 시간에 심각한 영향을 미치며 추적중인 문제이지만 ( swift-syntax #2421 참조) 현재 구현 된 솔루션은 없습니다.
import Defaults
import DefaultsMacros
@ Observable
final class UnicornManager {
@ ObservableDefault ( . hasUnicorn )
@ ObservationIgnored
var hasUnicorn : Bool
} Toggle SwiftUI.Toggle 래퍼도 있습니다.이 래퍼는 Bool 값의 Defaults 을 기반으로 토글을 쉽게 만들 수 있습니다.
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 (alias 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 으로 사용할 수 있습니다.
유형에는 Defaults.Bridge 준수하는 유형의 인스턴스를 참조 해야하는 정적 변수 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 : UserDefaults 에 저장된 유형.serialize : UserDefaults 에 저장하기 전에 실행됩니다.deserialize : UserDefaults 에서 값을 검색 한 후 실행됩니다. Defaults.AnySerializable Defaults . AnySerializable < Value : Defaults . Serializable > ( _ value : Value ) 유형 : class
Defaults.Serializable 을위한 유형 기반 래퍼.
get<Value: Defaults.Serializable>() -> Value? : userDefaults에서 Value 유형의 값을 검색하십시오.get<Value: Defaults.Serializable>(_: Value.Type) -> Value? : 검색하려는 Value 지정하십시오. 이것은 일부 모호한 경우에 유용 할 수 있습니다.set<Value: Defaults.Serializable>(_ newValue: Value) : Defaults.AnySerializable 에 대한 새 값을 설정합니다. Defaults.reset(keys…) 유형 : func
주어진 키를 기본값으로 다시 재설정하십시오.
또한 컬렉션에 키를 저장 해야하는 경우 유용 할 수있는 String Keys를 지정할 수도 있습니다. 컬렉션에 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
기본 UserDefaults 에 저장할 수있는 Collection .
Defaults 해제를 수행 할 수 있도록 초기화 init(_ elements: [Element]) 가 있어야합니다.
Defaults.SetAlgebraSerializable public protocol DefaultsSetAlgebraSerializable : SetAlgebra , Defaults . Serializable {
func toArray ( ) -> [ Element ]
} 유형 : protocol
기본 UserDefaults 에 저장할 수있는 SetAlgebra .
Defaults 직렬화를 수행 할 수 있도록 함수 func toArray() -> [Element] 있어야합니다.
Defaults 이미 많은 유형에 대한 내장 지원이 있지만 고유 한 사용자 정의 유형을 사용할 수 있어야합니다. 아래 가이드는 Defaults 으로 자신의 사용자 정의 유형을 만드는 방법을 보여줍니다.
struct User {
let name : String
let age : String
}Defaults.Bridge 준수하는 브리지를 만듭니다. 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
)
}
}Defaults.Serializable 준수하는 User 확장을 만듭니다. 정적 다리는 위에서 만든 다리가되어야합니다. 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 준수하는 값에 대해서만 사용할 수 있습니다.
경고 : 유형 에라저는 성능이 훨씬 나빠서 처리 할 수있는 다른 방법이 없을 때만 사용해야합니다. 포장 유형에서만 사용해야합니다. 예를 들어, Array , Set 또는 Dictionary 으로 싸여 있습니다.
Defaults.AnySerializable 것은 ExpressibleByStringLiteral , ExpressibleByFloatLiteral ExpressibleByIntegerLiteral byintegerliteral, expressiblebyfloatliteral, ExpressibleByBooleanLiteral , ExpressibleByNilLiteral , ExpressibleByArrayLiteral 및 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"
}더 많은 예는 테스트/defaultsanyserializabletests를 참조하십시오.
Codable 유형에 대한 직렬화 Codable & NSSecureCoding 또는 Codable & RawRepresentable 열거를 준수하는 유형이있을 수 있습니다. 기본적으로 Defaults Codable 적합성을 선호하고 CodableBridge 를 사용하여 JSON 문자열로 직렬화합니다. NSSecureCoding 데이터로 직렬화하거나 RawRepresentable Enum의 원시 값을 사용하려면 Defaults.PreferNSSecureCoding 준수 할 수 있습니다 .PrefernssSecurecoding 또는 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 ]
}
}Defaults.CollectionSerializable 준수하는 Bag 확장을 만듭니다. 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 )
}
}Defaults.SetAlgebraSerializable 준수하는 SetBag 확장을 만듭니다 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