Search code examples
xcodecocoacocoa-bindings

Binding to @count of an array in the user defaults


Is it possible to bind a Control to collection properties of an array stored in the user defaults?

I was attempting(in interface builder of Xcode 4.3) to bind the Max Value to the arrays count like this:

Max Value (Shared User Defaults Controller.values.MYArrayName.@count)
bind to: shared user defaults controller
controller key: values
Model key Path: MYArrayName.@count

Unfortunately this has no effect at all (not even any errors).

I can bind the Max Value to an ivar in the view controller then bind that to the value from the user defaults. e.g

NSUInteger maxVal
...

NSUserDefaults* stdUD=[NSUserDefaults standardUserDefaults];
[self bind:@"maxVal" toObject:stdUD withKeyPath:@"MYArrayName.@count" options:nil];

Then:

Max Value (File's owner.maxVal)
bind to: files owner
controller key:
Model key Path: maxVal

But I would have liked to do it with out the extra step


Solution

  • You can use the standardUserDefaults with Interface Builder, with 2 options:

    First Option

    In Interface Builder, drag in a User Defaults Controller to Objects.

    Then, drag in an NSArrayController, and name it something like "ArrayFromDefaultsController" (just for clarity's sake). Make sure it's mode is Class, and Class Name is NSArray (or NSMutableArray).

    In the bindings tab, under Content Array:

    Bind: User Defaults Controller

    Controller Key: values

    Model Key Path: <#your Key#>

    Go to your field, and bind it's Max Value:

    Bind: ArrayFromDefaultsController

    Controller Key: arrangedObjects

    Model Key Path: @count

    This simply creates an Array Controller that is bound the the array in your user defaults, and the field is bound to the count value of that Array Controller's arrangedObjects.

    Second Option

    Create an NSValueTransformer subclass (eg. ArrayCountValueTransformer), and in the class put this:

    +(Class)transformedValueClass {
        return [NSNumber class];
    }
    
    - (id)transformedValue:(id)value {
        if (value == nil) {
            return nil;
        } else {
            return [NSNumber numberWithInteger:[value count]];
        } 
    }
    

    This will automatically convert the count of your User Default's array to a value recognizable in the Model Key Path.

    Drag in a User Defaults Controller into the objects list. Then, in the field you want to bind (on Max Value):

    Bind:User Defaults Controller

    Controller Key: values

    Model Key Path: <#your key#> (no @count)

    Value Transformer: ArrayCountValueTransformer