Re: Property in class mirrored to user defaults
Re: Property in class mirrored to user defaults
- Subject: Re: Property in class mirrored to user defaults
- From: Jonathan Taylor <email@hidden>
- Date: Fri, 16 Jun 2017 17:49:21 +0100
Thankyou Charles and Keary for your replies. I somehow hadn't thought of using
NSDefaults as backing for the properties. There are a lot of properties
involved, but with a macro or something I should be able to set it up without a
massive code bloat. Will give that a go.
Cheers
Jonny
On 12 Jun 2017, at 16:01, Charles Srstka <email@hidden> wrote:
>> On Jun 12, 2017, at 4:04 AM, Jonathan Taylor <email@hidden>
>> wrote:
>>
>> Hi all,
>>
>> This feels like a very basic question, but one that I have not had any luck
>> searching for (maybe I am using the wrong terms?).
>>
>> At the moment I have properties in a (singleton) class that are bound to UI
>> elements. At the moment they have the same automatic values every time the
>> app is launched, although the user can change them while it is running. What
>> I would like is for the user's previous choice to be remembered when the app
>> is next launched. Obviously this would seem to be a job for NSUserDefaults.
>> I am not sure quite what the right way to structure things is, though.
>>
>> All the simple examples I have seen bind to NSUserDefaults and then if the
>> program actually wants to know what the value is, it simply accesses the
>> values directly on NSUserDefaults. I would prefer not to do that, though
>> (see below).
>>
>> What I ~think~ I would like is to still be able to access the values as
>> properties of my class. That seems to me like the natural way, and it would
>> seem odd to have two categories of value, some accessed through properties
>> on the class, and some accessed some other way via NSUserDefaults. However,
>> if I bind the UI elements to the shared user defaults object, is that not
>> what will happen? Or is there some way that I can "link" my class and the
>> user defaults object, so that the properties are saved in user defaults but
>> I can still access them in a fairly seamless way from my class? I do like
>> the idea of having the properties (and their types) explicitly declared as
>> part of my class, rather than being mysterious objects that only exist in
>> the user defaults.
>>
>> Does anyone have any advice on how I can achieve this, or on how I should be
>> thinking about all this differently?
>> Thanks
>> Jonny
>
> If performance isn’t an issue, as it usually isn’t for properties linked to
> UI elements, and you don’t want to bind the UI elements directly to an
> NSUserDefaultsController, you can just use UserDefaults as the backing for a
> property, like this:
>
> class MyClass: NSObject {
> // this is a property only so we can make key paths that will go
> through it
> @objc private let userDefaults: UserDefaults
> private static let fooDefaultsKey = "Foo"
>
> @objc private static let keyPathsForValuesAffectingFoo: Set<String> =
> ["\(#keyPath(userDefaults)).\(MyClass.fooDefaultsKey)"]
> @objc dynamic var foo: String {
> get { return UserDefaults.standard.string(forKey:
> MyClass.fooDefaultsKey) ?? "" }
> set { UserDefaults.standard.set(newValue, forKey:
> MyClass.fooDefaultsKey) }
> }
>
> override init() {
> self.userDefaults = UserDefaults.standard
>
> super.init()
> }
> }
>
> This is pretty cool; on recent releases of macOS, it’ll respond to changes in
> the defaults even if they come from outside the process. So, if you observe
> the “foo” property, and then manually use /usr/bin/defaults to change the
> defaults, your notifications in the app will fire.
>
> Alternately, you can just set up the property at init time and then update
> the defaults whenever it changes, like this. You won’t get the cool
> observation behavior, though, unless you use KVO’s infamously ugly
> observation APIs (the slick new closure-based one won’t work here, since
> we’re stuck with using string keys for this).
>
> class MyClass: NSObject {
> private static let fooDefaultsKey = "Foo"
>
> @objc dynamic var foo: String {
> didSet { UserDefaults.standard.set(self.foo, forKey:
> MyClass.fooDefaultsKey) }
> }
>
> override init() {
> self.foo = UserDefaults.standard.string(forKey:
> MyClass.fooDefaultsKey) ?? ""
>
> super.init()
> }
> }
>
> Charles
>
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden