views:

160

answers:

3

I have a pretty standard setup where I have an array in my controller that I'm binding to an NSTableView. When I add an object to this array with the UI, I add elements by copying the array to a mutable array, adding the contents, then copying it back. I saw this idiom somewhere, but I'm not really sure where, or whether this is actually a sane thing to do. I t works fine on Snow Leopard, but it crashes really badly on Leopard. GDB tells me it happens right at the marked line, where I copy the new array back.

@interface MyAppDelegate : NSObject {

    NSArray * urls;
    //other declarations
}
@property (nonatomic, retain) NSArray *urls;


@implementation MyAppDelegate 

@synthesize urls;

- (void)addThing:(id)sender {

    NSMutableArray *newUrls = [NSMutableArray arrayWithArray: [self urls]];

    [newUrls addObject: newurlimadding];
    [self setUrls: [NSArray arrayWithArray: newUrl]]; 
}

I'm pretty sure I must be doing something boneheaded here. Is there a better way to do this? Why am I crashing?

A: 

NSArray * things; - since this can be modified you better represent using NSMutableArray instead NSArray.

When ever you need to add some new element to the list just use 'addObject' and insert element to the list.

Your binding will make sure that UI is updated using KVO and KVC.

Girish Kolari
This didn't seem to solve the problem. When I added my new object, I was still getting a crash.
oldpatricka
did you created the array object in MyAppDelegate -> init method? make sure that before inserting an element to the object of NSMutableArray the array is created.
Girish Kolari
A: 

It looks like the problem was that I had NSURLs as my object type. Once I changed the object in my array to a custom-made KVC compliant object, I wasn't getting any more crashes.

Maybe NSURL isn't KVC-compliant on 10.5, but it is on 10.6?

oldpatricka
+1  A: 
NSMutableArray *newUrls = [NSMutableArray arrayWithArray: [self urls]];
[newUrls addObject: newurlimadding];
[self setUrls: [NSArray arrayWithArray: newUrl]];

What did you create newUrls for if not to set it as the new value of urls?

Besides that, there are a couple of things you're doing wrong:

  1. No model objects. Bindings hates this. Unless your table view exists solely to display the different parts of the URL (scheme, host, path, etc.), each in one column, you're not giving Bindings what it wants.

    Pay attention to the fields in the Bindings Inspector. Note that there are two: Controller Key and Model Key Path. They're exactly what they say on their tins: The Controller Key is the key for a property of the controller, which should provide model objects. The Model Key Path is the key path for one or more properties in the model, which usually should provide value objects, such as strings and numbers.

    You probably need to create a model class and make the URL a property of that class. I'd guess that you have other objects, perhaps in parallel arrays, that you can move to properties of the model class. Do that, so that you're working with Bindings instead of against it.

  2. Not using array accessors. You're just setting the whole array at once, which is inefficient and may cause display problems (such as selection highlights disappearing). Implement and use array accessors for this array property. Accessorizer can help you here.

I actually have no idea whether this will fix your crash because you haven't told us anything about it. You should edit your question to include any exception messages or other crash-describing output, which you'll find in the Run Log/Debugger Console.

Also, since the type of urls can be mutable, you should set it to copy, not retain.

Peter Hosey
Actually, my tableview *does* just have one column, and just displays the path of a URL. I bound the column to the path key in the NSURL object. This array of NSURLs is just sitting in my controller object, and it probably belongs in my model. If all I want is to show the path key in one table column, is there anything wrong with pointing bindings directly to an array of NSURLs? It "works" on 10.6.I knew there was probably a better way to add to the array though. Thanks. I'll read through the Model Object Implementation Guide.
oldpatricka
Also, I don't really know what useful thing I could post about the crash though, since the error console just gives me the boilerplate "gdb is starting" text (http://pastie.org/784091), and the debugger just points me to where I caused the crash. http://i.imgur.com/hxcwi.png
oldpatricka
Look at the frame number column in the Debugger window. That's at least four digits! You probably have a recursion problem. Look a bit higher in the stack and see what the cycle is.
Peter Hosey
Ah! It was because the array of URLs was set to retain, not copy, and I guess it was stuck in a loop of -[NSURL absoluteURL] and CFURLCopyAbsoluteURL . Once I changed those arrays to copy, not retain, it stopped crashing.Thanks a lot for your help!
oldpatricka
That's… strange. Glad it works now, though.
Peter Hosey