views:

108

answers:

3

new problem:

I am receiving this error: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'

In the ViewDidLoad I initialized my array:

id object = [[NSUserDefaults standardUserDefaults] objectForKey:@"array"];

    if (object) 
    {
        locationArray = object;
        NSLog(@"retrieved", object);
    }
    else 
    {
        locationArray = [[NSMutableArray alloc] init];
        NSLog(@"init");
    }

Then, I am trying to add the data to locationArray:

            ABMultiValueRef multi = ABRecordCopyValue(person, property);
            NSUserDefaults *locatie = [NSUserDefaults standardUserDefaults];

            // Set up an NSArray and copy the values in.
            NSArray *theArray = [(id)ABMultiValueCopyArrayOfAllValues(multi) autorelease];
            //everything goes fine the first time, but the second time i receive an error after at this code:
            [locationArray addObject:theArray];

            [locatie setObject:locationArray forKey:@"array"];

Every first time I select an address everything is fine. But every second time I am receiving that error. What did I do wrong?

A: 

And don't forget to check if fname is not nil before adding it to array

Andrew
+2  A: 
NSString *fname = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSMutableString *lname = (NSMutableString *)ABRecordCopyValue(person, kABPersonLastNameProperty);

What makes you think ABRecordCopyValue is going to return a mutable string here?

Just telling the compiler that it will return a mutable string (which is all “(NSMutableString *)” does) doesn't mean it will. If the Address Book documentation doesn't specify that this will return a mutable string, assume it won't and create a mutable string yourself.

Speaking of which…

NSMutableString *name = [[NSMutableString alloc] init];

Here's the string you should be appending to. You don't need lname to be mutable, because this string is mutable.

NSMutableString *space = @" ";
fname = [fname stringByAppendingFormat:space];
fname = [fname stringByAppendingFormat:lname];

By doing this, you waste the mutable string you created. You are creating two intermediate immutable strings here, not appending to the mutable string.

name = fname;

And here, you throw away the mutable string entirely (and thereby leak it since you never released it), replacing it with the immutable string you got from your series of stringByAppendingFormat: messages.

What you should do is send the name mutable string an appendFormat: message, passing both the first and last name strings. You don't need the space string; you can include that in the format string.

See also the NSMutableString docs.

[nameArray addObject:fname];

At no point prior to this statement have you created an NSMutableArray object and stored its pointer in the nameArray variable. Not in any code you've shown, anyway.

Until you do that, this variable holds nil, the pointer to no object. The addObject: message does nothing because that's what messages to nil do: Nothing. Logging the array you don't have produces “(null)” because that's the description of nil.

    if (nameArray == nil) {
        NSLog(@"NO DATA TO RETRIEVE FROM USERDEFAULTS");

You aren't showing any code that retrieves from user defaults. Even if you did, it would return an immutable array as Sven said; you would have to make a mutable copy.

This is the best I can do without a description of the problem. We may be able to provide more and better suggestions if you edit your question to tell us what happens when you run the above code, and not just what doesn't happen.

Peter Hosey
+1  A: 

The problem occures when you get the locationArray from the NSUserDefaults and try to insert some object ([locationArray addObject:theArray];). The object you get from the NSUserDefaults is not mutable, so you have to create a mutable copy:

NSMutableArray* locationArray = [[NSUserDefaults standardUserDefaults] objectForKey:@"array"];

if (locationArray != nil)
    locationArray = [[locationArray mutableCopy] autorelease];
else 
    locationArray = [NSMutableArray array];
Nikolai Ruhe