Resolved Fetch object in NSMutableDictionary inside NSMutable

Discussion in 'iOS Programming' started by lasash, Oct 5, 2012.

  1. lasash, Oct 5, 2012
    Last edited: Oct 8, 2012

    lasash macrumors member

    Joined:
    Sep 15, 2012
    #1
    Hello,

    I have somewhat of a silly problem:

    I am fetching a JSON array, which includes two-dimensional arrays;
    And I am adding them to an NSMutableDictionary inside NSMutableArray:

    Code:
        for (NSDictionary *s in [json objectForKey:@"inst"])
        {
            NSMutableDictionary *arr=[[NSMutableDictionary alloc] init];
            [arr setObject:[s objectForKey:@"i"] forKey:@"i"];
            [arr setObject:[s objectForKey:@"user_id"] forKey:@"userID"];
            [arr setObject:[s objectForKey:@"page_id"] forKey:@"pageID"];
            [arr setObject:[s objectForKey:@"page_dep_code"] forKey:@"pageDepName"];
            [arr setObject:[s objectForKey:@"link_url"] forKey:@"linkURL"];
            [arr setObject:[s objectForKey:@"page_header_1"] forKey:@"pageHeader"];
            [arr setObject:[s objectForKey:@"user_logo"] forKey:@"userLogo"];
            [arr setObject:[s objectForKey:@"link_name"] forKey:@"linkName"];
            [instNames addObject:arr];
        }
    
    Whereas "inst" is my multidimensional array, and it has an internal array which repeats itself (it's supposed to be a list of academic institutes, where each institute has ID, logo, name etc).

    Problem is, after creating the table view, I am trying to populate the rows, and it fails:

    Code:
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";
        
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
        }
        
    // this is the part where it fails
        NSMutableDictionary *tl=[[NSMutableDictionary alloc] initWithDictionary:[instNames objectAtIndex:[indexPath row]]];
    // end of failing part
        NSString *str=[tl valueForKey:@"pageHeader"];
        cell.textLabel.text=str;
        
        return cell;
    }
    
    I googled it for like 30 minutes and haven't found what I am doing wrong yet.

    Your help would be greatly appreciated.

    Thank you and have a great weekend,
    Liroy
     
  2. CodeBreaker macrumors 6502

    Joined:
    Nov 5, 2010
    Location:
    Sea of Tranquility
    #2
    What's the error/exception?

    Also, This makes no sense.

    Code:
    NSMutableDictionary *tl=[[NSMutableDictionary alloc] initWithDictionary:[instNames objectAtIndex:[indexPath row]]];
    
    Should be

    Code:
    NSMutableDictionary *tl = [instNames objectAtIndex:[indexPath row]];
    
     
  3. lasash thread starter macrumors member

    Joined:
    Sep 15, 2012
    #3
    Hi There!

    I fixed the code as you said. This is the exception:

    Code:
    2012-10-06 11:02:43.266 Studies Adviser[2940:c07] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFConstantString 0x124e8> valueForUndefinedKey:]: this class is not key value coding-compliant for the key pageHeader.'
    *** First throw call stack:
    (0x1ca3012 0x10e0e7e 0x1d2bfb1 0xb8d5ed 0xaf98db 0xaf988d 0x9ee1 0xe2f4b 0xe301f 0xcb80b 0xdc19b 0x7892d 0x10f46b0 0x229ffc0 0x229433c 0x2294150 0x22120bc 0x2213227 0x22138e2 0x1c6bafe 0x1c6ba3d 0x1c497c2 0x1c48f44 0x1c48e1b 0x1bfd7e3 0x1bfd668 0x2865c 0x287d 0x27a5)
    libc++abi.dylib: terminate called throwing an exception
    (lldb)
    
    Thanks!
     
  4. CodeBreaker macrumors 6502

    Joined:
    Nov 5, 2010
    Location:
    Sea of Tranquility
    #4
    Your code does not crash where you put the comments. It crashes because you are not retrieving your dictionary objects correctly. You are using setObject: forKey: for storing the objects and using valueForKey: for retrieving them.

    Replace this:
    Code:
    NSString *str=[tl valueForKey:@"pageHeader"];
    
    with this:

    Code:
    NSString *str=[tl objectForKey:@"pageHeader"];
    
     
  5. lasash thread starter macrumors member

    Joined:
    Sep 15, 2012
    #5
    Thanks for the fix.
    Now I get the following error:

    Code:
    2012-10-06 11:38:37.999 Studies Adviser[3238:c07] -[__NSCFConstantString objectForKey:]: unrecognized selector sent to instance 0x124e4
    2012-10-06 11:38:38.000 Studies Adviser[3238:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString objectForKey:]: unrecognized selector sent to instance 0x124e4'
    
    I am really clueless about what I am doing wrong...
    Thanks again!
     
  6. CodeBreaker macrumors 6502

    Joined:
    Nov 5, 2010
    Location:
    Sea of Tranquility
    #6
    Put this and see what exactly t1 is ( before objectForKey: )?

    Code:
    NSLog(@"%@", [t1 class]);
    
    I think your array actually contains strings instead of dictionaries.
     
  7. lasash thread starter macrumors member

    Joined:
    Sep 15, 2012
    #7
    2012-10-06 19:12:06.703 Studies Adviser[3551:c07] __NSCFConstantString
    2012-10-06 19:12:06.704 Studies Adviser[3551:c07] __NSDictionaryM
    2012-10-06 19:12:06.704 Studies Adviser[3551:c07] __NSDictionaryM

    OK, that's odd.
    I am supposed to get two results, and I get 3!
    The first line is confusing. This is my JSON:

    Code:
    {
        "page_dep_name": "MA Math",
        "page_id": "52",
        "inst": [
            {
                "i": "1",
                "user_id": "30",
                "page_id": "2462",
                "page_dep_code": "272",
                "link_url": "http://www.psychometry.co.il/smbk/ma-math-education.php",
                "page_header_1": "SMKB",
                "user_logo": "http://www.psychometry.co.il/uploaded_files/smbk.png",
                "link_name": "SMKB",
                "israel_area": "TA"
            },
            {
                "i": "2",
                "user_id": "90",
                "page_id": "1043",
                "page_dep_code": "39",
                "link_url": "http://www.psychometry.co.il/oranim/horaat-madaim-med.php",
                "page_header_1": "Oranim",
                "user_logo": "http://www.psychometry.co.il/uploaded_files/oranim.png",
                "link_name": "Oranim",
                "israel_area": "Tivon"
            }
        ]
    }
    
    That is weird! What else is the json fetching?
     
  8. CodeBreaker macrumors 6502

    Joined:
    Nov 5, 2010
    Location:
    Sea of Tranquility
    #8
    You, for some reason are adding a string to your inst array before you add the dictionaries. Can you add [inst removeAllObjects] before the for loop which adds the dictionaries?
     
  9. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #9
    To answer that, you'll have to tell us where the JSON text is coming from (a URL, a file, etc.), and exactly what JSON parser you're using. Better yet, post the code that fetches and parses the JSON text.

    If you want someone else to be able to see the same thing you're seeing, you have to post enough code and information for them to replicate it. Otherwise all anyone can do is guess. We can't see your files or your screen.
     
  10. lasash thread starter macrumors member

    Joined:
    Sep 15, 2012
    #10
    Thumbs up to that, you are right.
    Next time I will post the entire code

    Thanks!

    ----------

    Well, I feel really stupid at the moment...
    Apparently I added a NSString in the init line:
    Code:
    [NSMutableArray alloc] initWithObjects: 'test', nil];
    Now I deleted it and it works perfectly.
    CodeBreaker, thanks to you I now know how to check what class the object is (wasn't anywhere in the books).

    These tricks really help a beginner such as myself to overcome his debugging process.

    Problem Solved. THANK YOU!

    I now have to SubClass the Table cell with two labels and an image.
    Hopefully, no bugs here too :)

    Have a great weeked,
    Liroy
     
  11. CodeBreaker macrumors 6502

    Joined:
    Nov 5, 2010
    Location:
    Sea of Tranquility
    #11
    Glad it worked
     
  12. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #12
    Since you solved the problem, let me go back and do a brief code review.

    You posted this code:
    Code:
        for (NSDictionary *s in [json objectForKey:@"inst"])
        {
            NSMutableDictionary *arr=[[NSMutableDictionary alloc] init];
            [arr setObject:[s objectForKey:@"i"] forKey:@"i"];
            [arr setObject:[s objectForKey:@"user_id"] forKey:@"userID"];
            [arr setObject:[s objectForKey:@"page_id"] forKey:@"pageID"];
            [arr setObject:[s objectForKey:@"page_dep_code"] forKey:@"pageDepName"];
            [arr setObject:[s objectForKey:@"link_url"] forKey:@"linkURL"];
            [arr setObject:[s objectForKey:@"page_header_1"] forKey:@"pageHeader"];
            [arr setObject:[s objectForKey:@"user_logo"] forKey:@"userLogo"];
            [arr setObject:[s objectForKey:@"link_name"] forKey:@"linkName"];
            [instNames addObject:arr];
        }
    
    for working with this JSON text posted later:
    Code:
    {
        "page_dep_name": "MA Math",
        "page_id": "52",
        "inst": [
            {
                "i": "1",
                "user_id": "30",
                "page_id": "2462",
                "page_dep_code": "272",
                "link_url": "http://www.psychometry.co.il/smbk/ma-math-education.php",
                "page_header_1": "SMKB",
                "user_logo": "http://www.psychometry.co.il/uploaded_files/smbk.png",
                "link_name": "SMKB",
                "israel_area": "TA"
            },
            {
                "i": "2",
                "user_id": "90",
                "page_id": "1043",
                "page_dep_code": "39",
                "link_url": "http://www.psychometry.co.il/oranim/horaat-madaim-med.php",
                "page_header_1": "Oranim",
                "user_logo": "http://www.psychometry.co.il/uploaded_files/oranim.png",
                "link_name": "Oranim",
                "israel_area": "Tivon"
            }
        ]
    }
    
    When the code was originally posted, my first thought was, "I wonder if there's a simple way to express that." Having not yet seen the JSON text, I simply let it lie.

    Having now seen the JSON text, consider the following observations:
    1. Inside the 'for' loop, the variable 's' is an NSDictionary. As such it has the methods -copy and -mutableCopy.
    2. The extent of the item-by-item copying is such that only the "israel_area" key is omitted. Every other key/value is copied from 's' to a new mutable dictionary. (It's impossible to tell if the omission of "israel_area" is intentional or accidental (a bug).)
    3. Since the copied dictionary is mutable, you can remove objects from it.
    4. Given the above, a much simpler approach would be to:
      a. Get a mutable copy of the dictionary 's' (the -mutableCopy method).
      b. Remove the object for the "israel_area" key.


    While the above is a lot simpler, there is an even simpler approach:

    Assuming you're using NSJSONSerialization, there is an option for creating the JSON-object with mutable containers.

    So if the JSON object already has an NSMutableDictionary for each element of the "inst" array, and the "inst" array is an NSMutableArray, you can simply store the "inst" array object itself as the instNames variable. The array itself will be mutable, and the dictionaries it contains will also be mutable.

    You can, if you wish, go through and remove the "israel_area" object from every dictionary, or you could leave it as-is and simply ignore it. Hard to say which is more suitable without knowing how the keys are actually used.

    Alternatively, if the JSON-object is being shared by other parts of the code that might mutate it (change the array or dictionary contents), you can make a mutable copy of the "inst" array object.


    Finally, you originally said "two-dimensional arrays", but neither JSON nor Cocoa has such things. They both have one-dimensional arrays. A "two-dimensional array" in both cases is represented as an array of arrays. This may seem like a two-dimensional array, but it's fundamentally different.

    In this case, with this data, you don't even have an array of arrays. You have an array of dictionaries, which is not at all the same as a two-dimensional array, or an array of arrays. This is a fundamental misapprehension, and if you don't correct it I suspect it will eventually lead to later problems. If you already understand the difference, and simply miswrote "two-dimensional arrays", then all I can add is "Accuracy is important in programming".
     
  13. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #13
    Are you aware that UITableViewCell already provides two UILabels (textLabel and detailTextLabel) and an UIImageView (imageView)?
     
  14. lasash thread starter macrumors member

    Joined:
    Sep 15, 2012
    #14
    I am, but my image is 100x60 (w&h) and I don't know if the default cell style can fit itself to it.

    I was able to create the custom cell and populate it properly.
    I think it gives me more control of things in the future, don't you say?

    Thanks

    ----------

    WOW, this is an amazing review of my code!

    I come from PHP programming, where there's no such thing as Dictionary, so I used the terms I knew: array of arrays, or multidimentional-array.

    After some reading, I know the difference in Xcode, and please do correct me if I am mistaken:

    NSArray - A simple array of values with no keys (keys are intergers)
    NsMutableArray - Array with key-value pair.

    NSDictionary - A simple dictionary of values with no key identifier (keys are string)

    NSDIctionary - Dictionary of key-value pairs, where the key is a string.

    Can you pls link me to the documantion of the NJJSONSerialization, where you can create automatically the NSDictionary?

    Thanks again for the code review! It was a very important reading for me as a beginner.
     
  15. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #15
    It can, if you set your row height appropriately.

    Well, that's true. I'll grant you that.
     
  16. lasash thread starter macrumors member

    Joined:
    Sep 15, 2012
    #16
    It's good to know about this default style, and next time when I need label-sublabel-image structure, I will use that.

    But I'm thinking of the future, always
     
  17. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #17
    But don't over-complicate the present for some future that, in your estimation, is unlikely. A default table cell could make development much easier for now, if you see little chance of needing anything else, and it should be rather easy to migrate to a custom cell in the future, should you come to the conclusion that it becomes necessary.
     
  18. lasash thread starter macrumors member

    Joined:
    Sep 15, 2012
    #18
    You are right my friend.

    However, as a programmer before, I know that once you create one module, you can use it for other projects, and by doing so, you build yourself a personal repository which makes programming faster and easier.

    I wanted to have a custom cell implementation so that in the future, I could just copy-paste-modify it to my needs.
     
  19. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #19
    Correct.

    Incorrect. NSMutableArray is that same as NSArray, but dynamic rather than static. This means you can add, remove, or replace elements.

    P.S. It's NSMutableArray. The case of the 's' is important, because case is significant in Objective-C!

    Incorrect. NSDictionary does have key identifiers, and they are not restricted to strings. It's something known as key-value pairing.

    I suspect you mean NSMutableDictionary here. Again, as with NSMutableArray, NSMutableDictionary is dynamic.

    How do you normally try to find things in the documentation? I'm not trying to avoid the question; I just want to make sure that you are using the usual techniques to search the documentation.
     
  20. lasash thread starter macrumors member

    Joined:
    Sep 15, 2012
    #20
    I don't like Apple's documantation that much. I usually google: "Xcode+short desc of my problem"
     
  21. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #21
    Please explain why not.

    Also please point to an example that you dislike. If it's a class reference doc, such as the NSJSONSerialization class reference, please explain exactly why you dislike it.


    To better understand NSArray, NSDictionary, and their mutable subclasses, you should start by reading the Cocoa Fundamentals Guide. It will tell you about fundamentals in Cocoa's design, like the distinction between a mutable and immutable class (a pattern that arises multiple times, in different areas).

    Next, you should read the Collections Programming Topics, which has a description of all the collections classes. On the left, in the blue vertical bar will be links to individual class references. Use those to learn the details of a specific class.

    BTW, much of this documentation is directly available in Xcode. If you don't know how to use it, or dislike it for some reason, you will be at a significant disadvantage.

    There are other tools for reference docs, like:
    http://appkido.com/
    The docs themselves are the same, they haven't been rewritten. Only the interface for searching them is different.
     
  22. lasash thread starter macrumors member

    Joined:
    Sep 15, 2012
    #22
    I am just thinking that by googling my problem, I find the solution faster, and many times I come to this forum via google results and fin my answer directly. I use the documentation by apple only when I must, but coming from the PHP world, where there's a great documentation in PHP.net website, but I find myself preferring the unofficial W3C tutorials, you can see my logic.
     
  23. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #23
    Frankly, I can't see your logic at all.

    First, you haven't explained why you dislike Apple's documentation. If there is a problem, you need to explain what it is.

    Second, no tutorial covers every detail of a class. You will eventually have to read class reference docs, because no tutorial covers everything. Tutorials often omit things in order to simplify for beginners. This does not mean the omissions are unimportant; in fact, they can be very important for effective use of the class, like the mutable-collections option for NSJSONSerialization. Furthermore, there is no better reference for any of the classes than Apples docs. There are some that are simpler, but none are as comprehensive nor as authoritative.

    In addition, Apple's online class references are often structured with links to related Companion Guides in the blue left-hand column. For example, refer to the NSArray class reference (google search terms NSArray class reference ios), and look at the left-hand column with the blue background. At the bottom is the COMPANION GUIDES heading, and under that the first item is the Collections Programming Guide I previously linked to.
     

Share This Page