NSUserDefaults Implementation

Referring to macoslib and some forum postings, I tried to assemble a process in which I could store settings using NSUserDefaults. I haven’t been able to get it to work. I think there is some kind’ve initialization required that I am missing. This is OS X.8.5 and Xojo 2013r3.3.

I create a Ptr to NSUserDefaults, and store it in a module property.

Declare Function standardUserDefaults Lib "Cocoa.framework" Selector "standardUserDefaults" ( NSUserDefaultsClass As Ptr ) As Ptr ptrStandardUserDefaults = standardUserDefaults( NSClassFromString( "NSUserDefaults" ) )

I set a fake preference:

Declare Sub setObject Lib "Cocoa.framework" Selector "setObject:forKey:" ( NSUserDefaults As Ptr, value As CFStringRef, key As CFStringRef ) setObject( ptrStandardUserDefaults, "Dummy_Setting, "The_Setting" )

When the app quits, I call Synchronize:

Declare Sub synchronize lib "Cocoa.framework" selector "synchronize" (id as Ptr) synchronize( ptrStandardUserDefaults )

After the app has quit, I go to the command line and try and view my fake settings:

defaults read com.mycompany.myfakeapp

I get a message that my domain doesn’t exist. Where am I going wrong?

(I wish to avoid third-party plugins.)

Why not use the CFPreferences API already exposed in macoslib? It’s the same thing as NSUserDefaults, just that CFPreferences is the C-based CoreFoundation API and NSUserDefaults is the higher level Objective-C API.

“synchronize” is a function, not a sub. It returns 0 (error) and 1 (success).

Declare Function synchronize Lib "Foundation" Selector "synchronize" (NSUserDefaults As Ptr) As Byte

[quote=67693:@Eli Ott]“synchronize” is a function, not a sub. It returns 0 (error) and 1 (success).

Declare Function synchronize Lib "Foundation" Selector "synchronize" (NSUserDefaults As Ptr) As Byte

There’s actually no need to synchronize, NSUserDefaults take care of that.

Joe: a big yes and small no. While the app is running: yes, no need to call it - no, because:

But what I meant was, that he could try synchronize as a function to know if an error happens.
Another remark: when the app has closed, it can take several seconds, until the preferences file is updated on disk.

[quote=67699:@Eli Ott]J…what I meant was, that he could try synchronize as a function to know if an error happens.
Another remark: when the app has closed, it can take several seconds, until the preferences file is updated on disk.[/quote]

Eli: the value of Byte after the call to Synchronize is zero.

My understanding is that it should return YES if there is success, and NO if there has been a failure. I assume zero means failure.

macoslib is a huge asset to our community, and I am enormously grateful for the work that Charles and many others have contributed for our collective benefit. It is breathtaking in scope and quality.

But – as far as I can tell (and don’t hesitate to correct me) – I can’t just “use CFPreferences” in macoslib. I have to add either the entire macoslib library to my project or at least large sections of it. Because of the size of macoslib (21k lines), I am loathe to do this for the benefits of a single class. On my somewhat dated hardware, it takes 27 seconds to open the macoslib project. To me, that’s a fairly big deal.

Yes, 0 means NO, 1 means YES. So synchronizing fails.

Have you tested in the debugger that ptrStandardUserDefaults is not zero?

Wrap your code in Try-Catch with

Try // put your code here Catch err As ObjCException? BREAK // if you get here, err.Message will show you the Objective C error End

[quote=67744:@Eli Ott]Yes, 0 means NO, 1 means YES. So synchronizing fails.
Have you tested in the debugger that ptrStandardUserDefaults is not zero?
[/quote]

Aha! When I changed an If/then statement earlier today, I inadvertently turned off the code that initialized NSUserDefaults. So it was not really extant when I called the subsequent related processes.

I am now successfully writing/reading settings, and the results of the defaults command are as expected.

Thanks for your help!

It would be great if someone could post this to xippets as it is a commonly asked question.

The example project that houses MacOSLib takes longer to load than a project with the macoslib folder installed. Here, the example project takes 15 seconds to load but a project with just the macoslib folder takes 8 seconds.

On my somewhat dated equipment, it takes about 15 secs to load a project with just the macoslib folder.