I have found various references on this list and on the web about the 
impossibility to hook up an *editable* single-column NSTableView to an 
NSMutableArray of strings via bindings - and about some clever ways to work 
around this limitation. These workarounds may work in principle, but fail in a 
NSUserDefaultsController-NSArrayController-NSTableView setup.

I tried to be exceedingly clever using the following category (as proposed by 
Joanna Carter http://carterconsulting.org.uk/forums/viewtopic.php?f=3&t=14):

@interface NSMutableString (KVCHelper) 
@property (copy) NSString *string;
@end

@implementation NSMutableString (KVCHelper)
@dynamic string;
- (NSString *) string{
   return self;
} 
@end

alongside with various NSValueTransformers converting strings or arrays to 
their mutable variants, as well as converting the array to a mutable dictionary 
and back using this one

#import "ArrayOfStringsToArrayOfMutableDictionariesVT.h"
#define kStringKey @"stringKey"

@implementation ArrayOfStringsToArrayOfMutableDictionariesVT
+ (Class) transformedValueClass
{
        return [NSMutableArray class];
}

+ (BOOL) allowsReverseTransformation
{
        return YES;
}

- (id) transformedValue:(id)array
{
   NSMutableArray *myMutableArray = [[NSMutableArray alloc] 
initWithCapacity:[array count]];
   for (NSString *myString in array) {
      [myMutableArray addObject:[NSMutableDictionary 
dictionaryWithObject:myString forKey:kStringKey]];
   }
   return [myMutableArray autorelease];
}

- (id) reverseTransformedValue:(id)array
{
   NSMutableArray *myMutableArray = [[NSMutableArray alloc] 
initWithCapacity:[array count]];
   for (NSDictionary *myDictionary in array) {
      [myMutableArray addObject:[myDictionary objectForKey:kStringKey]];
   }
   return [myMutableArray autorelease];
}
@end

All to no avail, they work but don't help. The dead end is always 
NSUserDefaults, or more precisely its controller. It's such a pain that you can 
save an NSArray in user defaults but then nevertheless be unable to access it 
using bindings.

So my question is:

How could I possibly wrap an NSArray in the user defaults in a way that I can 
conveniently access it via bindings to populate an editable NSTableView? Is 
there a way to wrap an NSArray into some kind of opaque data object, so that 
the array controller is prevented from accessing single items in the array, but 
instead receives it from and hands it over to the user defaults controller in a 
single item lump?

My point is: I'd like to abandon saving an NSArray in the user defaults if I 
can use something similarly ordered and access it via bindings instead. I know 
I could create a wrapper class for each string element in the array, but I 
wonder if there isn't an easier solution choosing a different container object.

There is still a rumor about the NSUserDefaultsController yielding immutable 
objects and this being one source for this problem. That's untrue. It seems to 
have changed with OS 10.4. I can write data from a table view to the 
applications preferences plist, but the data type is wrong - the string "test" 
(set via the table view in the GUI) is wrapped into a dictionary on write, 
whereas the rest (set programmatically on initialization) are simple strings:

{
    fruitsList =     (
                {
            abc = test;
        },
        Orange,
        Strawberry,
        Raspberry,
        Whatnot
    );
}
 
OK - this was the pointer to myself - silly...

I converted my original array of strings (= myArray) to a mutable array of 
mutable dictionaries, each containing a single string under some arbitrary key 
(which has to be kept constant for all these dictionaries, of course). So my 
+initialize method looks as follows:

   NSArray *myArray = [NSMutableArray arrayWithObjects:@"Apple", @"Orange", 
@"Strawberry", @"Raspberry", @"Whatnot", nil];
   NSMutableArray *myMutableArray = [[NSMutableArray alloc] 
initWithCapacity:[myArray count]];
   for (NSString *myString in myArray) {
      [myMutableArray addObject:[NSMutableDictionary 
dictionaryWithObject:myString forKey:@"abc"]];
   }
   
   NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
                                myMutableArray,
                                @"fruitsList", 
                                nil];
   
   [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];

And my application prefs plist looks like this:
{
    fruitsList =     (
                {
            abc = Apple;
        },
                {
            abc = Orange;
        },
                {
            abc = Strawberry;
        },
                {
            abc = Raspberry;
        },
                {
            abc = Whatnot;
        }
    );
}

Setting the model key path for the table column to abc (while checking Handles 
Content as Compound Value) makes it possible to access and edit all these 
strings via bindings.

Is there a more elegant/efficient solution than looping over the array and then 
once again into the opposite direction for real use outside the prefs (I could 
use a block in 10.6, I know)?
At least it works and it's a lot better than writing all the glue code. There 
is also no need to write and use a wrapper class.

Sorry for having answered my own question in such a long winded manner - and 
again thanks for any pointers to alternative 
approaches!_______________________________________________

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to