Giter VIP home page Giter VIP logo

swiftyuserdefaults's Introduction

SwiftyUserDefaults

Platforms CI Status CocoaPods compatible Carthage compatible SPM compatible Swift version Swift version Swift version Swift version

Modern Swift API for NSUserDefaults

SwiftyUserDefaults makes user defaults enjoyable to use by combining expressive Swifty API with the benefits of static typing. Define your keys in one place, use value types easily, and get extra safety and convenient compile-time checks for free.

Previous versions' documentation: Version 4.0.0, Version 3.0.1
Migration guides: from 4.x to 5.x, from 4.0.0-alpha.1 to 4.0.0-alpha.3, from 3.x to 4.x

Version 5.0.0

FeaturesUsageCodableNSCodingRawRepresentableExtending existing typesCustom types

Property wrappersKVOdynamicMemberLookupLaunch argumentsUtilsInstallation

Features

There's only one step to start using SwiftyUserDefaults:

Define your keys!

extension DefaultsKeys {
    var username: DefaultsKey<String?> { .init("username") }
    var launchCount: DefaultsKey<Int> { .init("launchCount", defaultValue: 0) }
}

And just use it ;-)

// Get and set user defaults easily
let username = Defaults[\.username]
Defaults[\.hotkeyEnabled] = true

// Modify value types in place
Defaults[\.launchCount] += 1
Defaults[\.volume] -= 0.1
Defaults[\.strings] += "… can easily be extended!"

// Use and modify typed arrays
Defaults[\.libraries].append("SwiftyUserDefaults")
Defaults[\.libraries][0] += " 2.0"

// Easily work with custom serialized types
Defaults[\.color] = NSColor.white
Defaults[\.color]?.whiteComponent // => 1.0

If you use Swift 5.1 - good news! You can also use keyPath dynamicMemberLookup:

Defaults.color = NSColor.white

See more at the KeyPath dynamicMemberLookup section.

Usage

Define your keys

To get the most out of SwiftyUserDefaults, define your user defaults keys ahead of time:

let colorKey = DefaultsKey<String>("color", defaultValue: "")

Just create a DefaultsKey object, put the type of the value you want to store in angle brackets, the key name in parentheses, and you're good to go. If you want to have a non-optional value, just provide a defaultValue in the key (look at the example above).

You can now use the Defaults shortcut to access those values:

Defaults[key: colorKey] = "red"
Defaults[key: colorKey] // => "red", typed as String

The compiler won't let you set a wrong value type, and fetching conveniently returns String.

Take shortcuts

For extra convenience, define your keys by extending magic DefaultsKeys class and adding static properties:

extension DefaultsKeys {
    var username: DefaultsKey<String?> { .init("username") }
    var launchCount: DefaultsKey<Int> { .init("launchCount", defaultValue: 0) }
}

And use the shortcut dot syntax:

Defaults[\.username] = "joe"
Defaults[\.launchCount] += 1

Supported types

SwiftyUserDefaults supports all of the standard NSUserDefaults types, like strings, numbers, booleans, arrays and dictionaries.

Here's a full table of built-in single value defaults:

Single value Array
String [String]
Int [Int]
Double [Double]
Bool [Bool]
Data [Data]
Date [Date]
URL [URL]
[String: Any] [[String: Any]]

But that's not all!

Codable

Since version 4, SwiftyUserDefaults support Codable! Just conform to DefaultsSerializable in your type:

final class FrogCodable: Codable, DefaultsSerializable {
    let name: String
 }

No implementation needed! By doing this you will get an option to specify an optional DefaultsKey:

let frog = DefaultsKey<FrogCodable?>("frog")

Additionally, you've got an array support for free:

let froggies = DefaultsKey<[FrogCodable]?>("froggies")

NSCoding

NSCoding was supported before version 4, but in this version we take the support on another level. No need for custom subscripts anymore! Support your custom NSCoding type the same way as with Codable support:

final class FrogSerializable: NSObject, NSCoding, DefaultsSerializable { ... }

No implementation needed as well! By doing this you will get an option to specify an optional DefaultsKey:

let frog = DefaultsKey<FrogSerializable?>("frog")

Additionally, you've got an array support also for free:

let froggies = DefaultsKey<[FrogSerializable]?>("froggies")

RawRepresentable

And the last but not least, RawRepresentable support! Again, the same situation like with NSCoding and Codable:

enum BestFroggiesEnum: String, DefaultsSerializable {
    case Andy
    case Dandy
}

No implementation needed as well! By doing this you will get an option to specify an optional DefaultsKey:

let frog = DefaultsKey<BestFroggiesEnum?>("frog")

Additionally, you've got an array support also for free:

let froggies = DefaultsKey<[BestFroggiesEnum]?>("froggies")

Extending existing types

Let's say you want to extend a support UIColor or any other type that is NSCoding, Codable or RawRepresentable. Extending it to be SwiftyUserDefaults-friendly should be as easy as:

extension UIColor: DefaultsSerializable {}

If it's not, we have two options:
a) It's a custom type that we don't know how to serialize, in this case at Custom types
b) It's a bug and it should be supported, in this case please file an issue (+ you can use custom types method as a workaround in the meantime)

Custom types

If you want to add your own custom type that we don't support yet, we've got you covered. We use DefaultsBridges of many kinds to specify how you get/set values and arrays of values. When you look at DefaultsSerializable protocol, it expects two properties in each type: _defaults and _defaultsArray, where both are of type DefaultsBridge.

For instance, this is a bridge for single value data storing/retrieving using NSKeyedArchiver/NSKeyedUnarchiver:

public struct DefaultsKeyedArchiverBridge<T>: DefaultsBridge {

    public func get(key: String, userDefaults: UserDefaults) -> T? {
        userDefaults.data(forKey: key).flatMap(NSKeyedUnarchiver.unarchiveObject) as? T
    }

    public func save(key: String, value: T?, userDefaults: UserDefaults) {
        userDefaults.set(NSKeyedArchiver.archivedData(withRootObject: value), forKey: key)
    }

    public func deserialize(_ object: Any) -> T? {
        guard let data = object as? Data else { return nil }
        return NSKeyedUnarchiver.unarchiveObject(with: data) as? T
    }    
}

Bridge for default storing/retrieving array values:

public struct DefaultsArrayBridge<T: Collection>: DefaultsBridge {
    public func save(key: String, value: T?, userDefaults: UserDefaults) {
        userDefaults.set(value, forKey: key)
    }

    public func get(key: String, userDefaults: UserDefaults) -> T? {
        userDefaults.array(forKey: key) as? T
    }

    public func deserialize(_ object: Any) -> T? {
        nil
    }
}

Now, to use these bridges in our type we simply declare it as follows:

struct FrogCustomSerializable: DefaultsSerializable {

    static var _defaults: DefaultsKeyedArchiverBridge( { DefaultsKeyedArchiverBridge() }
    static var _defaultsArray: DefaultsKeyedArchiverBridge { DefaultsKeyedArchiverBridge() }

    let name: String
}

Unfortunately, if you find yourself in a situation where you need a custom bridge, you'll probably need to write your own:

final class DefaultsFrogBridge: DefaultsBridge {
    func get(key: String, userDefaults: UserDefaults) -> FrogCustomSerializable? {
        let name = userDefaults.string(forKey: key)
        return name.map(FrogCustomSerializable.init)
    }

    func save(key: String, value: FrogCustomSerializable?, userDefaults: UserDefaults) {
        userDefaults.set(value?.name, forKey: key)
    }

    func deserialize(_ object: Any) -> FrogCustomSerializable? {
        guard let name = object as? String else { return nil }

        return FrogCustomSerializable(name: name)
    }
}

final class DefaultsFrogArrayBridge: DefaultsBridge {
    func get(key: String, userDefaults: UserDefaults) -> [FrogCustomSerializable]? {
        userDefaults.array(forKey: key)?
            .compactMap { $0 as? String }
            .map(FrogCustomSerializable.init)
    }

    func save(key: String, value: [FrogCustomSerializable]?, userDefaults: UserDefaults) {
        let values = value?.map { $0.name }
        userDefaults.set(values, forKey: key)
    }

    func deserialize(_ object: Any) -> [FrogCustomSerializable]? {
        guard let names = object as? [String] else { return nil }

        return names.map(FrogCustomSerializable.init)
    }
}

struct FrogCustomSerializable: DefaultsSerializable, Equatable {

    static var _defaults: DefaultsFrogBridge { DefaultsFrogBridge() }
    static var _defaultsArray: DefaultsFrogArrayBridge { DefaultsFrogArrayBridge() }

    let name: String
}

To support existing types with different bridges, you can extend it similarly:

extension Data: DefaultsSerializable {
    public static var _defaultsArray: DefaultsArrayBridge<[T]> { DefaultsArrayBridge() }
    public static var _defaults: DefaultsDataBridge { DefaultsDataBridge() }
}

Also, take a look at our source code (or tests) to see more examples of bridges. If you find yourself confused with all these bridges, please create an issue and we will figure something out.

Property wrappers

SwiftyUserDefaults provides property wrappers for Swift 5.1! The property wrapper, @SwiftyUserDefault, provides an option to use it with key path and options: caching or observing.

Caching means that we will store the value for you and do not hit the UserDefaults for value almost never, only for the first value fetch.

Observing means we will observe, via KVO, your property so you don't have to worry if it was saved somewhere else and you use caching.

Now usage! Given keys:

extension DefaultsKeys {
    var userColorScheme: DefaultsKey<String> { .init("userColorScheme", defaultValue: "default") }
    var userThemeName: DefaultsKey<String?> { .init("userThemeName") }
    var userLastLoginDate: DefaultsKey<Date?> { .init("userLastLoginDate") }
}

You can declare a Settings struct:

struct Settings {
    @SwiftyUserDefault(keyPath: \.userColorScheme)
    var userColorScheme: String

    @SwiftyUserDefault(keyPath: \.userThemeName, options: .cached)
    var userThemeName: String?

    @SwiftyUserDefault(keyPath: \.userLastLoginDate, options: [.cached, .observed])
    var userLastLoginDate: Date?
}

KVO

KVO is supported for all the types that are DefaultsSerializable. However, if you have a custom type, it needs to have correctly defined bridges and serialization in them.

To observe a value for local DefaultsKey:

let nameKey = DefaultsKey<String>("name", defaultValue: "")
Defaults.observe(key: nameKey) { update in
	// here you can access `oldValue`/`newValue` and few other properties
}

To observe a value for a key defined in DefaultsKeys extension:

Defaults.observe(\.nameKey) { update in
	// here you can access `oldValue`/`newValue` and few other properties
}

By default we are using [.old, .new] options for observing, but you can provide your own:

Defaults.observe(key: nameKey, options: [.initial, .old, .new]) { _ in }

KeyPath dynamicMemberLookup

SwiftyUserDefaults makes KeyPath dynamicMemberLookup usable in Swift 5.1!

extension DefaultsKeys {
    var username: DefaultsKey<String?> { .init("username") }
    var launchCount: DefaultsKey<Int> { .init("launchCount", defaultValue: 0) }
}

And just use it ;-)

// Get and set user defaults easily
let username = Defaults.username
Defaults.hotkeyEnabled = true

// Modify value types in place
Defaults.launchCount += 1
Defaults.volume -= 0.1
Defaults.strings += "… can easily be extended!"

// Use and modify typed arrays
Defaults.libraries.append("SwiftyUserDefaults")
Defaults.libraries[0] += " 2.0"

// Easily work with custom serialized types
Defaults.color = NSColor.white
Defaults.color?.whiteComponent // => 1.0

Launch arguments

Do you like to customize your app/script/tests by UserDefaults? Now it's fully supported on our side, statically typed of course.

Note: for now we support only Bool, Double, Int, String values, but if you have any other requests for that feature, please open an issue or PR and we can talk about implementing it in new versions.

You can pass your arguments in your schema:

Pass launch arguments in Xcode Schema editor.

Or you can use launch arguments in XCUIApplication:

func testExample() {
    let app = XCUIApplication()
    app.launchArguments = ["-skipLogin", "true", "-loginTries", "3", "-lastGameTime", "61.3", "-nickname", "sunshinejr"]
    app.launch()
}

Or pass them as command line arguments!

./script -skipLogin true -loginTries 3 -lastGameTime 61.3 -nickname sunshinejr

Utils

Remove all keys

To reset user defaults, use removeAll method.

Defaults.removeAll()

Shared user defaults

If you're sharing your user defaults between different apps or an app and its extensions, you can use SwiftyUserDefaults by overriding the Defaults shortcut with your own. Just add in your app:

var Defaults = DefaultsAdapter<DefaultsKeys>(defaults: UserDefaults(suiteName: "com.my.app")!, keyStore: .init())

Check key

If you want to check if we've got a value for DefaultsKey:

let hasKey = Defaults.hasKey(\.skipLogin)

Installation

Requirements

Swift version >= 4.1
iOS version >= 9.0
macOS version >= 10.11
tvOS version >= 9.0
watchOS version >= 2.0

CocoaPods

If you're using CocoaPods, just add this line to your Podfile:

pod 'SwiftyUserDefaults', '~> 5.0'

Install by running this command in your terminal:

pod install

Then import the library in all files where you use it:

import SwiftyUserDefaults

Carthage

Just add to your Cartfile:

github "sunshinejr/SwiftyUserDefaults" ~> 5.0

Swift Package Manager

Just add to your Package.swift under dependencies:

let package = Package(
    name: "MyPackage",
    products: [...],
    dependencies: [
        .package(url: "https://github.com/sunshinejr/SwiftyUserDefaults.git", .upToNextMajor(from: "5.0.0"))
    ],
    targets: [...]
)

More like this

If you like SwiftyUserDefaults, check out SwiftyTimer, which applies the same swifty approach to NSTimer.

You might also be interested in my blog posts which explain the design process behind those libraries:

Contributing

If you have comments, complaints or ideas for improvements, feel free to open an issue or a pull request.

Authors and license

Maintainer: Łukasz Mróz

Created by: Radek Pietruszewski

SwiftyUserDefaults is available under the MIT license. See the LICENSE file for more info.

swiftyuserdefaults's People

Contributors

alec-c4 avatar askari01 avatar balestrapatrick avatar delba avatar divinedominion avatar eitot avatar esqarrouth avatar fredpi avatar hiroakit avatar jklausa avatar jschmid avatar kaunteya avatar kevinvitale avatar kohtenko avatar kyleleneau avatar laevandus avatar ldiqual avatar ls-philippe-casgrain avatar marty-suzuki avatar mathiasnagler avatar max-potapov avatar maximkhatskevich avatar narfdotpl avatar ohbargain avatar radex avatar rinatkhanov avatar staticdreams avatar sunshinejr avatar xavi-matos avatar z-jade avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swiftyuserdefaults's Issues

Is there a way to purge?

Hi, This is more like a question...

Is there any way to fully restart the information saved?

For example if a have an App and the user log-out I would like to reset all stored values, actually I have to go through every value in order to delete it.

No member named .xValue

When I try to use the Defaults["lastPaths"].arrayValue notation it throws an error saying: NSUserDefaults.Proxy does not have a member named arrayValue

I have copied the example from the readme, and it doest the same for all .xValues. When I remove Value from the end it works again.

Inline documentation

A lot of SwiftyUserDefaults isn't well documented in code. It's documented on the GitHub page, but it would be great it you could alt+click on any SUD symbol in Xcode and have a decent description of it.

PR-s are most welcome ;)

xCode 6.3 Beta compiler warning

I am using SwiftyUserDefaults within my Swift project. Unfortunately your project is producing a compiler warning:

´[...]/Pods/:1:1: Umbrella header for module 'SwiftyUserDefaults' does not include header 'SwiftyUserDefaults-Swift.h'´

Unfortunately I am very new to Swift and CocoaPods and I am aware that everything is still in beta, but It would be great to resolve the warning, so my project stays clean.

Thank you.

Best approach to observe changes?

Any ideas on how to best observe changes in the user defaults? Is there a good approach to integrate with KVO or NSNotificationCenter?

Why not use generics?

I don't think you mentioned this in your post, but sorry if you did. Wouldn't generics be helpful for this so there wouldn't be so much specific type casting?

set Optional before the string

Hello guys, I'm a beginner on your framework, I have one trouble..

I try to set

Defaults["signupName"] = "test"

and get

var name = Defaults["signupName"].string

when I show 'name'

logWarning("name: \(name)")

it return

signup(): name: Optional("test")

Thank for your work ;)

Carthage support

I've tried setting this up, but didn't manage to get it to work.

Syntax error while using shortcuts

this code will compile error

extension DefaultsKeys {
    static let username = DefaultsKey<String?>("username")
    static let launchCount = DefaultsKey<Int>("launchCount")
}

image

i use Xcode 7.1

Objective-C support ?

Yes, I know, it's a bit strange but SwiftyUserDefaults is a great solution for an Objective-C app I am currently refactoring.

Swift 1.2 - Endless loop

Hi,
thanks for this awesome library. I have an issue when checking for a nil value.
Though there is the "hasKey" approach, I would suggest to provide the nil check for convenience reasons. I don't know if my proposed solution has any side effects

if Defaults["firstInstallDate"] == nil {
    // causes endless loop
}

if Defaults.hasKey("firstInstallDate") == nil {
    // works fine
}

public subscript(key: String) -> Any? {
        get {
            return self[key] <---- this is the problem
        }
…

public subscript(key: String) -> Any? {
        get {
            return objectForKey(key) <---- this rewriting works fine
        }
…

Cocoapods missing 1.2

I tried to setup this package with CocoaPods, but the site says the latest version is 1.1.

Analyzing dependencies
[!] Unable to satisfy the following requirements:

- `SwiftyUserDefaults (~> 1.2.0)` required by `Podfile`

Add public initializer to Proxy

The Proxy class has no public initializer, only a private one.

Thus it cannot be overriden and mocked because Swift requires you to call super.init.
It also cannot be instantiated in custom code due to the private accessibility of the initializer.

Type of expression is ambiguous without more context

Can someone help me why i am getting this error message at compile time.

import SwiftyUserDefaults

extension DefaultsKeys {

    static let latestProjects = DefaultsKey<[[String: AnyObject]]?>("latestProjects")

}

// Error: Type of expression is ambiguous without more context
Defaults[.latestProjects] = projectsJson 

NSURL setter & getter

Great helper. but missing NSURL :

    public var url : NSURL? {
        return defaults.URLForKey(key)
    }

    public var urlValue : NSURL {
        return defaults.URLForKey(key) ?? NSURL()
    }

Support for tvOS

With the new Apple TV, the support for tvOS would be great. :)

Carthage build failed

Version 2.1.2 - iOS platform

*** Fetching SwiftyUserDefaults
*** Checking out SwiftyUserDefaults at "2.1.2"
*** xcodebuild output can be found in /var/folders/mw/c_9_2r_j0v39wmprr8t02mn00000gn/T/carthage-xcodebuild.0drq2y.log
*** Building scheme "SwiftyUserDefaults" in SwiftyUserDefaults.xcodeproj
** BUILD FAILED **


The following build commands failed:
    CompileSwift normal arm64 /Carthage/Checkouts/SwiftyUserDefaults/Tests/SwiftyUserDefaultsTests.swift
    CompileSwift normal arm64 /Carthage/Checkouts/SwiftyUserDefaults/Tests/TestHelper.swift
    CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler
(3 failures)
/Carthage/Checkouts/SwiftyUserDefaults/Tests/SwiftyUserDefaultsTests.swift:2:18: error: module 'SwiftyUserDefaults' was not compiled for testing

Also, when will deprecated operators be removed ?
Carthage update get alot of messages like this

Carthage/Checkouts/SwiftyUserDefaults/Tests/SwiftyUserDefaultsTests.swift:48:24: warning: '?=' is deprecated: Please migrate to static keys and use this gist: https://gist.github.com/radex/68de9340b0da61d43e60

/Carthage/Checkouts/SwiftyUserDefaults/Tests/SwiftyUserDefaultsTests.swift:117:24: warning: '+=' is deprecated: Please migrate to static keys to use this.

iOS 7 bug

On iOS 7, if I don't use synchronize, settings are not applied. I think you should either update documentation or add synchronize.

Add watchOS support

Would be great to have support for watchOS via Carthage — like #53 and tvOS.

Help appreciated!

List open bugs.swift.org issues

SwiftyUserDefaults is really held back by Swift's weaknesses (like the lack of generic subscripts). Would be nice to add a section at the end of readme to list those issues with links to bugs.swift.org

NSArray instead of Array

Why are NSArray & NSDictionary used instead of native value types Array and Dictionary?

NSUserDefaults also return value types as seen in the code below

class NSUserDefaults : NSObject {
    func arrayForKey(defaultName: String) -> [AnyObject]?
    func dictionaryForKey(defaultName: String) -> [NSObject : AnyObject]?
}

Is there any specific reason for returning NSArray and NSDictionary in Proxy class

public var array: NSArray?
public var dictionary: NSDictionary?

Using suiteName?

Awesome work, thx for sharing!

I looked at the source code and read your blog post about it, but couldn't figure a good way to extend for optionally using suiteName. Do you have any suggestions for making this work with NSUserDefaults(suiteName: "my.storage.key")?

It doesn't seem like it would be a trivial change because synchronize() would have to be called in every set, and also still allow to use NSUserDefaults.standardUserDefaults() optionally.

I did something like this here, but I really like your API :). Maybe something like Defaults[SUITE_NAME_CONSTANT][.username]?

Complex NSObject

Thanks for sharing this! I found this repos awesome! :D
Anyway, I think I need more complex data to be store e.g.

Defaults["bar"] = NSKeyedArchiver.archivedDataWithRootObject([100:"foo", 2:"b", 3:["foo":"bar"]])
var bar: AnyObject? = NSKeyedUnarchiver.unarchiveObjectWithData(Defaults["bar"].data!)
println(bar)

It success but as you can see, it would be nice if we make it shorter.
Feel free to close this btw, I just think out loud tho :D

Thanks!

appending Int

extension DefaultsKeys {
static let favorites = DefaultsKey<[Int]?>("favorites")
}
//////
Defaults[.favorites]?.append(100)
print(Defaults[.favorites])


Why is printing nil?

Question: How does this sync?

Normally this is called after each user default operation:

    NSUserDefaults.standardUserDefaults().synchronize()

However I didn't see this called, how does SwiftyUD handle this?

Registering defaults while setting DefaultsKey

Can we consider registering default value to every static key while initialising

For eg:

let colorKey = DefaultsKey<String, UIColor>(["color": UIColor.grayColor()])

Where key named "color" would be set and default value would be set to gray using register user defaults

Autocompletion

This code which is recommended does not autocomplete:

    var userDefault = Defaults[.userId]

It is very much useless if it does not autocomplete. I don't want to check the file where I created my keys to figure out what to write, I want xcode to give me the options and let me select.

This works and autocompletes:

    var userDefault = Defaults[DefaultsKeys.userId]

But, this does not work:
http://prntscr.com/8wdxum

Obviously there is a bad design decision on the name. Please change it so it is clear what Keys and Key does.

Maybe some shortcut like:

    var userDefault = Defaults[Defs.userId]

might be useful, or if it is possible its best to get rid of the part before dot all together.

I personally made a 200 loc user defaults helper class myself. I am abandoning mine and using this cause I see great potential. The only downside is its not as convenient and easy as it can be.

Support Swift value types

The official custom type support requires NSCoding, which rules out value types. Currently I’m working around this by using the legacy string API in a subscript extension and converting the value type to & from built-in codable types.

It would be nice to have a better solution for this - support for RawRepresentable would cover a lot of cases, but having the ability to support arbitrary value types via some sort of codable type conversion protocol would be nicer.

Why not have a .value property on DefaultsKey?

Accessing Defaults[prop] sounds like extra work compared to prop.value. It also gives rise to a bunch of seemingly unnecessary magic like defining the keys on extension DefaultsKey.

Non-nil enums allowed?

I have the following:

extension DefaultsKeys {
    static let theme = DefaultsKey<ThemeOptions>("theme")
}
enum ThemeOptions: Int {
    case dark
    case light
}

extension NSUserDefaults {
    subscript(key: DefaultsKey<ThemeOptions>) -> ThemeOptions {
        get { return unarchive(key) ?? .dark }
        set { archive(key, newValue) }
    }
}

I'm getting this error from unarchive() when the value is nil (not set):
Could not cast value of type 'NSTaggedPointerString' to 'NSNumber'

Is there a way to do non-nil enums?

It time to merge the Swift 1.2 branch

Now Swift 1.2 is out, it's time for a new release. Please 😃

For the record, for now I use the branch this way:

pod 'SwiftyUserDefaults', :git => 'https://github.com/radex/SwiftyUserDefaults', :branch => 'swift-1.2'

no such module 'SwiftyUserDefaults'

Hi,
Installed via Cocoapods and Podfile , (gem install cocoapods --pre Fetching: cocoapods-core 0.37.0.beta.1.gem (100%)) xCode Version 6.3 (6D570)

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'SwiftHTTP', '> 0.9.4'
pod 'JSONJoy-Swift', '
> 0.9.2'
pod 'SwiftyUserDefaults'

SwiftHTTP and other is working , when i add import SwiftyUserDefaults that time gives no such module SwiftyUserDefaults

Thank you

Make "non-bool" to "bool" more consistent

First let me say that I really like what you're doing here. Good stuff.

One thing that seems a bit off is the way strings are not converted to bool values, but doubles and ints are.

For example, this seems odd...
Defaults["string1"] = "foo"
assert(Defaults["string1"].bool == nil)

When this also passes:
Defaults["int1"] = 100
assert(Defaults["int1"].bool == true)

I would expect this to pass for consistency:
assert(Defaults["string1"].bool == true)

I know this opens up other considerations, for example:
Default["string2"] = "true"
Default["string3"] = "false"
Default["string4"] = ""
Default["string5"] = "maybe"

Thoughts?

edit: Or maybe the another option would be to prevent numbers from being interpreted as bool values?

First launch activity

Many times it happens that we need to do some things only on first execution of app (like user onboarding.)

I usually end up with some thing like this

let introKey = DefaultsKey<Bool>("showIntro")

if Defaults[introKey] == false {
     doSomeActivityOnlyForFirstLaunch
     Defaults[introKey] = true
}

I use this pattern very frequently.


Assuming I am not doing anything wrong in above code, I propose a convenience function

Defaults.oneTimeAction(key: DefaultsKey<Bool>, f: () -> ())

Here is the code snippet which I have tried out

extension NSUserDefaults {
    func oneTimeAction(key: DefaultsKey<Bool>, f: () -> ()) {
        if !Defaults.hasKey(key) {
            f()
            Defaults[key] = true
        }
    }
}

Defaults.oneTimeAction(DefaultsKey<Bool>("showIntro")) { () -> () in
    print("This will be printed only on the first Launch")
}

or DefaultsKey can be made inside the method which leads to

Defaults.oneTimeAction("showIntro") { () -> () in
    print("This will be printed only on the first Launch")
}

Default dateValue

There can be something like

Defaults["today"].dateValue

which will return NSDate() if no date object is found

Carthage build warnings

ld: warning: directory not found for option '-F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/Developer/Library/Frameworks'

Similar problem
1.

/Carthage/Checkouts/SwiftyUserDefaults/SwiftyUserDefaultsTests/SwiftyUserDefaultsTests.swift:44:23: warning: '?=' is deprecated: Please migrate to static keys and use this gist: https://gist.github.com/radex/68de9340b0da61d43e60
1.

//Carthage/Checkouts/SwiftyUserDefaults/SwiftyUserDefaultsTests/SwiftyUserDefaultsTests.swift:72:24: warning: '+=' is deprecated: Please migrate to static keys to use this.

/Carthage/Checkouts/SwiftyUserDefaults/SwiftyUserDefaultsTests/SwiftyUserDefaultsTests.swift:86:23: warning: '++' is deprecated: Please migrate to static keys to use this.

Memory leaks

http://prntscr.com/ao2w98

This repo has some memory leaks it seems. They weren't anything big in my project to care much about but some others might have problems. Its worth taking a look. I'm using Instruments in this ss

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.