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 <cocoa...@charlessoft.com> wrote:

>> On Jun 12, 2017, at 4:04 AM, Jonathan Taylor <jonathan.tay...@glasgow.ac.uk> 
>> 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 (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

Reply via email to