logixologist
logixologist

Reputation: 3834

Adding a NSDictionary to a NSArray duplicates the first NSDictionary every time

So I pulled some JSON data from a web service which is stored in an NSArray called _infoFromJSON. Each array element in _infoFromJSON essentially has a dictionary of key/value pairs. The goal is to add them to myVehicleObject which is an NSMutableArray

for (NSDictionary* myDictionary in _infoFromJSON) {
    myVehicleObject *vehicleInMembersProfile;
    vehicleInMembersProfile = [[myVehicleObject alloc] init];
    vehicleInMembersProfile.make = [[_infoFromJSON objectAtIndex:carCount] objectForKey:@"make"];
    vehicleInMembersProfile.carName = [[_infoFromJSON objectAtIndex:carCount] objectForKey:@"nickname"];
    vehicleInMembersProfile.year = [[_infoFromJSON objectAtIndex:carCount] objectForKey:@"year"];
    carCount ++;
    [self.myVehicleObject addObject:vehicleInMembersProfile] ;
};

With the above code I sort of achieved it, however it keeps adding the same 1st dictionary to myVehicleObject, so it inserts the same NSDictionary 4 times In the past I have used this:

[self.myVehicleObject addObject:[vehicleInMembersProfile copy]] ;

When I do it it throws the following exception:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[myVehicleObject copyWithZone:]: unrecognized selector sent to instance 0xab4e130'

What am I doing wrong here? Thanks!

Update Requested Sample JSON:

{
        color = SILVER;
        engine = "";
        id = "CF270B81-3821-4585-8C90-7089D7A8654E";
        imageUrl = "https://www.someprotectedurl.com/somefile.png";
        licensePlate = "ABC-123";
        make = Honda;
        model = "CR-V";
        nickname = "My CR-V";
        vin = "XX551234687687687654";
        year = 2009;
    }

Upvotes: 0

Views: 76

Answers (3)

meda
meda

Reputation: 45500

I would probably use a for loop rather than a foreach since you need the array index, I would code it like this

NSMutableArray *vehiclesArray = [[NSMutableArray alloc]init];
for (int i = 0; i < [_infoFromJSON count]; i++)
{
    //create vehicle
    myVehicleObject *vehicleInMembersProfile = [[myVehicleObject alloc] init];
    vehicleInMembersProfile.make = _infoFromJSON[i][@"make"];
    vehicleInMembersProfile.carName = _infoFromJSON[i][@"nickname"];
    vehicleInMembersProfile.year = _infoFromJSON[i][@"year"];

    //finally add the vehicle to the array
    [vehiclesArray addObject:vehicleInMembersProfile] ;
}

I wasn't sure what myVehicleObject was , and why is it the same type you are adding to itself, so I changed it to an array. But you get the point.

Upvotes: 1

Chuck
Chuck

Reputation: 237110

The error is that your class does not implement NSCopying.

However, there isn't any need to copy the object here. You're creating a new object each time through the loop. If you insert a copy, you're just pointlessly throwing away the original each time. The more likely cause if you're seeing odd loop behavior is that your loop is mixing up different kinds of enumeration, as pointed out by nhgrif. Instead of accessing [_infoFromJSON objectAtIndex:carCount], just use myDictionary.

Upvotes: 2

nhgrif
nhgrif

Reputation: 62062

This may or may not be related to the problem, but your forin loop is completely broken. Whether or not your incorrect usage is the actual cause of the problem, this is something you should definitely fix as it can do nothing but cause problems.

If you want to use indexOfObject: to grab an object at an index of the array you're iterating through, you should use a regular for loop:

for (int carCount=0; index < [_infoFromJSON count]; ++carCount) {
    // loop body remains identical to what you have... 
    // except remove carCount++;
}

But for what you're doing, a forin loop is indeed better, and forin loops can be faster since they can be handled in batches. But if you're using a forin loop, use the object you're defining in the loop declaration:

for(NSDictionary* myDictionary in _infoFromJSON) {
    // myDictionary is a reference to an object in _infoFromJSON, 
    //for whatever given index it is currently working on

    myVehicleObject *vehicleInMembersProfile = [[myVehicleObject alloc] init];
    vehicleInMembersProfile.make = myDictionary[@"make"];
    vehicleInMembersProfile.carName = myDictionary[@"nickname"];
    vehicleInMembersProfile.year = myDictionary[@"year"];
    [self.myVehicleObject addObject:vehicleInMembersProfile];
}

Upvotes: 6

Related Questions