Re: Property in class mirrored to user defaults

2017-06-12 Thread Charles Srstka
> On Jun 12, 2017, at 4:04 AM, Jonathan Taylor  
> 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 = 
["\(#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 (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Property in class mirrored to user defaults

2017-06-12 Thread Jonathan Taylor
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
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com