It looks like you're new here. If you want to get involved, click one of these buttons!
NSArray *actors = [NSArray arrayWithObjects:@Brad Pitt, @William H. Macy, @Jennifer Aniston, nil];Still just strings, still quite easy to read. But now we've started to complicate things a bit, and certain downstream tasks get harder. Let's say I wanted to sort this list by last name. That's going to be a challenge, since each full name is a single string. I would need a way to identify the last name within the string. I could potentially carve each string into pieces, and take the second piece. But that would give me "H." for Mr. Macy. Ok, so I need to take the last piece instead. That should work as long as I haven't inadvertently entered "Pitt, Brad" somewhere.
NSMutableDictionary *actor = [NSMutableDictionary dictionary]; [actor setObject:@Brad forKey:@firstName]; [actor setObject:@"" forKey:@middleName]; [actor setObject:@Pitt forKey:@lastName];The string has been broken up into pieces, and can now be located via an identifier, the key. Retrieving a value is relatively simple:
NSString *actorFirstName = [actor objectForKey:@firstName];
NSArray *actors = [NSArray arrayWithObjects:actor1, actor2, actor3, nil];There are ways of sorting arrays using these keys, so it would seem that we've solved our problem. For now, at any rate.
NSDictionary *actor = [actors objectAtIndex:2];Ok, so you're referencing a single dictionary in an array, and you're calling it an actor. Great. Now then, what should "actor" have in it? Hrm, well, I sort of remember caring about the names, so probably names. Maybe their birthdays. Oh, it would be nice if there was a list of their movies too. I probably thought that was a good idea when I made this, so I'll just assume this data is there. Wonder what I called it. Probably "birthday". Great, let's see what happens:
NSString *birthday = [actor objectForKey:@birthday]; NSLog(@birthday is: %@", birthday); // Log output: birthday is: (null)Uh oh. It's not there. I must have called it something else. And come to think of it, would it really be an NSString? It's a date, and we have NSDate objects. Might have been one of those. How can I find out? Well, I could log the entire dictionary:
NSLog(@actor is: %@", [actor description])Hrm, no birthday. Is that because I didn't have information for this actor, or is that because none of the actors have birthdays? Not sure. And there isn't a handy way to find out, either. All I can do is figure out where I first created these dictionaries, and see what is there.
// I hereby define an "actor" dictionary as containing the following data: // First name shall be an NSString stored with the key "firstName" // Middle name shall be an NSString stored with the key "middleName" // Last name shall be an NSString stored with the key "lastName"You could, but no one takes the time to do this. And because dictionaries are so handy and flexible, you can add and remove keys all day long, and totally forget to update this list, at which point the list just becomes another point of confusion, rather than an aid. Without this list, you do not have an easy way to figure out what this dictionary should contain. You will have to waste time researching your own code and doing logging just to figure out what this should be.
NSString *firstName = [actor objectForKey:@firstName]; NSString *lastName = [actor objectForKey:@lastName]; NSString *fullName = [NSString stringWithFormat:@%@ %@", firstName, lastName];Blech. That's a lot of code, copy-pasted all over the place. And I forgot the middle initial. And sometimes it outputs "Bob (null)". So I need to make it more complicated, add some error handling, and then re-copy-paste it all over the place. Ah ha! I know a little about OOP, I'll just make a helper method somewhere. The only thing I know how to grab from anywhere is the app delegate, so I'll put it there!
- (NSString *)fullNameFromActor:(NSDictionary *)actor;Brilliant! Well, not so much. I mean, this will of course work. But look how far separated it is from your data. All of these actors are defined way over in some view controller (or better yet, a data controller) somewhere, but this method is here in the app delegate. Any time that you have one of these dictionaries in your hand, you have to go all the way over to the app delegate to get this method. More advanced programmers might be tempted to move this code into a Category, and that's certainly an option, but a bit beyond the scope of this article and not a good solution for a case like this anyway.