Dion
Dion

Reputation: 3335

Objective-C foreach for creating a NSDictionary not working

I'm trying to sort a NSDictionary with the following code:

NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableLeaves error:&err];
for (NSDictionary* lesson in jsonDict[@"data"][@"lessons"]) {
    data[lesson[@"day"]][lesson[@"index"]][@"title"] = lesson[@"title"];
}

If I log the values of lesson[@"day"] and so on, the values seem to be correct. Somehow if I log data[@"1"][@"1"] after the loop it's just empty. So the problems seems to be setting the values into the NSDictionary data.

The original JSON string contains a list with all lessons. To access them correctly I want to have a new NSDictionary in this format: data[day][index][field]

The JSON code looks like this:

{"status":"success","data":{"lessons":[{"id":1,"index":"1","day":"1","title":"Mathe","teacher":"Mr. xyz","room":"103","ind":"1"},{"id":2,"index":"1","day":"2","title":"Physik","teacher":"Mr xyz","room":"PH4","ind":"1"},...

Upvotes: 0

Views: 737

Answers (2)

Martin R
Martin R

Reputation: 539745

The problem is (I assume) that

data[lesson[@"day"]][lesson[@"index"]][@"title"] = lesson[@"title"];

does not automatically create the intermediate dictionaries

data[lesson[@"day"]]
data[lesson[@"day"]][lesson[@"index"]]

You have to check first if they exist, and assign a mutable dictionary if they don't yet exist. (There is no Autovivification as with Perl hashes!) Something like:

if (data[lesson[@"day"]] == nil) {
    data[lesson[@"day"]] = [NSMutableDictionary dictionary];
}
if (data[lesson[@"day"]][lesson[@"index"]] == nil) {
    data[lesson[@"day"]][lesson[@"index"]] = [NSMutableDictionary dictionary];
}
data[lesson[@"day"]][lesson[@"index"]][@"title"] = lesson[@"title"];

Complete working code:

NSString *str = @"{\"status\":\"success\",\"data\":{\"lessons\":[{\"id\":1,\"index\":\"1\",\"day\":\"1\",\"title\":\"Mathe\",\"teacher\":\"Mr. xyz\",\"room\":\"103\",\"ind\":\"1\"},{\"id\":2,\"index\":\"1\",\"day\":\"2\",\"title\":\"Physik\",\"teacher\":\"Mr xyz\",\"room\":\"PH4\",\"ind\":\"1\"}]}}";
NSError *err;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableLeaves error:&err];
NSMutableDictionary *data = [NSMutableDictionary dictionary];

for (NSDictionary* lesson in jsonDict[@"data"][@"lessons"]) {
    if (data[lesson[@"day"]] == nil) {
        data[lesson[@"day"]] = [NSMutableDictionary dictionary];
    }
    if (data[lesson[@"day"]][lesson[@"index"]] == nil) {
        data[lesson[@"day"]][lesson[@"index"]] = [NSMutableDictionary dictionary];
    }
    data[lesson[@"day"]][lesson[@"index"]][@"title"] = lesson[@"title"];
}
NSLog(@"%@", data);

Output:

{
    1 =     {
        1 =         {
            title = Mathe;
        };
    };
    2 =     {
        1 =         {
            title = Physik;
        };
    };
}

Upvotes: 2

gnasher729
gnasher729

Reputation: 52538

NSJSONSerialization creates dictionaries and arrays filled with other dictionaries, arrays, and values of type NSString, NSNumber, or NSNull.

You should re-think your strategy of writing hugely complex lines of code, but extract things one by one, to make it less confusing, and to make it possible to debug. Like

NSDictionary* data = jsonDict [@"data"];
NSArray* lessons = data [@"lessons"];

for (NSDictionary* lesson in lessons)
{
    NSString* lessonDay = lesson [@"day"];
    ...
}

and so on (it will also make your code run a lot quicker if you don't lookup the same thing again and again and again and again).

Now to where your bug is: dict [@"key"] = data; calls setObject:forKey: . However, dict [@"key1"] [@"key2"] calls objectForKey: @"key1" on the dictionary, that will give you a nil value, and then setObjectForKey: will be called with a nil receiver.

Upvotes: 1

Related Questions