Hierarchical defaults in NSUserDefaults?

  • I've been searching the web for an answer to this, and maybe I'm just
    not using the right search terms...

    I'd prefer not to put all of my defaults into the root level of my
    preferences file-- it saves me encoding namespaces into the default's
    key, and hopefully will allow me to pull a dictionary from the
    defaults database to hand to an initializer in one chunk.  I can't
    get it to bind properly though.

    Stripping it down to a basic example, I've got my app delegate with
    the following code:
    #import "appDel.h"

    @implementation appDel

    +(void)initialize
    {
      NSUserDefaults* appDefaults=[NSUserDefaults standardUserDefaults];
      NSMutableDictionary* myDefaults=[NSMutableDictionary dictionary];

      [myDefaults setValue:[NSMutableDictionary dictionary]
    forKey:@"testPath"];
      [myDefaults setValue:[NSMutableDictionary dictionary]
    forKeyPath:@"testPath.blah"];
      [myDefaults setValue:@"3.14" forKeyPath:@"testPath.blah.pi"];

      [appDefaults registerDefaults:myDefaults];
      //check dictionary structure
      [myDefaults writeToFile:[@"~/test.plist"
    stringByExpandingTildeInPath] atomically:true];
    }

    @end

    In the main window in the nib file, I have a single text box bound to
    Shared User Defaults, controller key is "values", and model key path
    is "testPath.blah.pi".

    When I run, the test.plist file I create in the initialize method is
    what I'd expect-- it's a plist file containing a dictionary called
    "testPath", containing a dictionary called "blah" containing a string
    called "pi" equal to "3.14".

    Problem is my text box comes up blank.  When I enter a value, that
    value is retained, but my "com.yourcompany.defaultsTest.plist"
    preferences file contains only a string called "testPath.blah.pi"
    which is equal to whatever I put in that text box.

    Why isn't my Model Key Path being parsed into it's component
    elements, and how do I convince the controller to do so?

    Thanks--
      Greg
  • I never got a response on this, but I think I've found a solution:

    I've added an additional NSObjectController to the NIB, binding it's
    contentObject binding to SharedDefaults, controller key "values",
    model key path "testPath".  I rewired my text box to point to the
    NSObjectController, controller key "selection", model key path
    "blah.pi".  Having done this, the text box comes up as 3.14.

    The next problem was that changing the value didn't cause the plist
    to be written to Preferences, but it appears that checking "Handles
    Content as Compound Value" does the trick.  Now the plist is written
    and remembered when the application is relaunched.

    The downside of this is I'll need to instantiate a separate
    controller for each group of preferences I create, but that should be
    manageable as my Preferences window has its own NIB file.

    Hopefully this will help someone else searching the archives.  If
    anyone has any comments on my approach, I'd be interested in hearing
    them.

    Cheers--
      Greg

    On Jul 25, 2007, at 12:21 AM, Greg Best wrote:

    > I've been searching the web for an answer to this, and maybe I'm
    > just not using the right search terms...
    >
    > I'd prefer not to put all of my defaults into the root level of my
    > preferences file-- it saves me encoding namespaces into the
    > default's key, and hopefully will allow me to pull a dictionary
    > from the defaults database to hand to an initializer in one chunk.
    > I can't get it to bind properly though.
    >
    > Stripping it down to a basic example, I've got my app delegate with
    > the following code:
    > #import "appDel.h"
    >
    > @implementation appDel
    >
    > +(void)initialize
    > {
    > NSUserDefaults* appDefaults=[NSUserDefaults standardUserDefaults];
    > NSMutableDictionary* myDefaults=[NSMutableDictionary dictionary];
    >
    > [myDefaults setValue:[NSMutableDictionary dictionary]
    > forKey:@"testPath"];
    > [myDefaults setValue:[NSMutableDictionary dictionary]
    > forKeyPath:@"testPath.blah"];
    > [myDefaults setValue:@"3.14" forKeyPath:@"testPath.blah.pi"];
    >
    > [appDefaults registerDefaults:myDefaults];
    > //check dictionary structure
    > [myDefaults writeToFile:[@"~/test.plist"
    > stringByExpandingTildeInPath] atomically:true];
    > }
    >
    > @end
    >
    > In the main window in the nib file, I have a single text box bound
    > to Shared User Defaults, controller key is "values", and model key
    > path is "testPath.blah.pi".
    >
    > When I run, the test.plist file I create in the initialize method
    > is what I'd expect-- it's a plist file containing a dictionary
    > called "testPath", containing a dictionary called "blah" containing
    > a string called "pi" equal to "3.14".
    >
    > Problem is my text box comes up blank.  When I enter a value, that
    > value is retained, but my "com.yourcompany.defaultsTest.plist"
    > preferences file contains only a string called "testPath.blah.pi"
    > which is equal to whatever I put in that text box.
    >
    > Why isn't my Model Key Path being parsed into it's component
    > elements, and how do I convince the controller to do so?
    >
    > Thanks--
    > Greg
  • I had a similar issue and never came up with your solution.  That's
    why I was excited to see NSDictionaryController in Leopard. :)

    I think it helps in this regard, though I haven't had an opportunity
    to try it out yet.

    Topher

    On Jul 29, 2007, at 7:36 AM, Greg Best wrote:

    > I never got a response on this, but I think I've found a solution:
    >
    > I've added an additional NSObjectController to the NIB, binding
    > it's contentObject binding to SharedDefaults, controller key
    > "values", model key path "testPath".  I rewired my text box to
    > point to the NSObjectController, controller key "selection", model
    > key path "blah.pi".  Having done this, the text box comes up as 3.14.
    >
    > The next problem was that changing the value didn't cause the plist
    > to be written to Preferences, but it appears that checking "Handles
    > Content as Compound Value" does the trick.  Now the plist is
    > written and remembered when the application is relaunched.
    >
    > The downside of this is I'll need to instantiate a separate
    > controller for each group of preferences I create, but that should
    > be manageable as my Preferences window has its own NIB file.
    >
    > Hopefully this will help someone else searching the archives.  If
    > anyone has any comments on my approach, I'd be interested in
    > hearing them.
    >
    > Cheers--
    > Greg
    >
    >
    > On Jul 25, 2007, at 12:21 AM, Greg Best wrote:
    >
    >> I've been searching the web for an answer to this, and maybe I'm
    >> just not using the right search terms...
    >>
    >> I'd prefer not to put all of my defaults into the root level of my
    >> preferences file-- it saves me encoding namespaces into the
    >> default's key, and hopefully will allow me to pull a dictionary
    >> from the defaults database to hand to an initializer in one
    >> chunk.  I can't get it to bind properly though.
    >>
    >> Stripping it down to a basic example, I've got my app delegate
    >> with the following code:
    >> #import "appDel.h"
    >>
    >> @implementation appDel
    >>
    >> +(void)initialize
    >> {
    >> NSUserDefaults* appDefaults=[NSUserDefaults standardUserDefaults];
    >> NSMutableDictionary* myDefaults=[NSMutableDictionary dictionary];
    >>
    >> [myDefaults setValue:[NSMutableDictionary dictionary]
    >> forKey:@"testPath"];
    >> [myDefaults setValue:[NSMutableDictionary dictionary]
    >> forKeyPath:@"testPath.blah"];
    >> [myDefaults setValue:@"3.14" forKeyPath:@"testPath.blah.pi"];
    >>
    >> [appDefaults registerDefaults:myDefaults];
    >> //check dictionary structure
    >> [myDefaults writeToFile:[@"~/test.plist"
    >> stringByExpandingTildeInPath] atomically:true];
    >> }
    >>
    >> @end
    >>
    >> In the main window in the nib file, I have a single text box bound
    >> to Shared User Defaults, controller key is "values", and model key
    >> path is "testPath.blah.pi".
    >>
    >> When I run, the test.plist file I create in the initialize method
    >> is what I'd expect-- it's a plist file containing a dictionary
    >> called "testPath", containing a dictionary called "blah"
    >> containing a string called "pi" equal to "3.14".
    >>
    >> Problem is my text box comes up blank.  When I enter a value, that
    >> value is retained, but my "com.yourcompany.defaultsTest.plist"
    >> preferences file contains only a string called "testPath.blah.pi"
    >> which is equal to whatever I put in that text box.
    >>
    >> Why isn't my Model Key Path being parsed into it's component
    >> elements, and how do I convince the controller to do so?
    >>
    >> Thanks--
    >> Greg

previous month july 2007 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Go to today