It looks like you're new here. If you want to get involved, click one of these buttons!
Straightforward, easy to read, a good starting point. If we were discussing table views, then it would be simple to take this array and use it to drive a table view. That's more than sufficient for static display, and helps to establish concepts. Another example:
NSArray *colorList = [NSArray arrayWithObjects:@"Blue", @"Green", @"Red", 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.
NSArray *actors = [NSArray arrayWithObjects:@"Brad Pitt", @"William H. Macy", @"Jennifer Aniston", nil];
The string has been broken up into pieces, and can now be located via an identifier, the key. Retrieving a value is relatively simple:
NSMutableDictionary *actor = [NSMutableDictionary dictionary];
[actor setObject:@"Brad" forKey:@"firstName"];
[actor setObject:@"" forKey:@"middleName"];
[actor setObject:@"Pitt" forKey:@"lastName"];
Now instead of putting strings into an array, add dictionaries instead:
NSString *actorFirstName = [actor objectForKey:@"firstName"];
There are ways of sorting arrays using these keys, so it would seem that we've solved our problem. For now, at any rate.
NSArray *actors = [NSArray arrayWithObjects:actor1, actor2, actor3, nil];
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:
NSDictionary *actor = [actors objectAtIndex:2];
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:
NSString *birthday = [actor objectForKey:@"birthday"];
NSLog(@"birthday is: %@", birthday);
// Log output: birthday is: (null)
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.
NSLog(@"actor is: %@", [actor description])
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.
// 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"
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 *firstName = [actor objectForKey:@"firstName"];
NSString *lastName = [actor objectForKey:@"lastName"];
NSString *fullName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
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.
- (NSString *)fullNameFromActor:(NSDictionary *)actor;