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