views:

1886

answers:

4

This one is a bit tedious in as far as explaining, so here goes. I'm essentially populating a tableView on the iPhone with multiple sections, and potentially multiple rows per section. To my understanding, it's best to have an array of arrays so that you can simply determine how many sections one has by sending a message to the top level array of count, then for rows per section, doing the same for the inner array(s). My data is in the form of a dictionary. One of the key/value pairs in the dictionary determines where it will be displayed on the tableView. An example is the following:

{
  name: "bob",
  location: 3
}
{ 
  name: "jane",
  location: 50
}
{
  name: "chris",
  location: 3
}

In this case I'd have an array with two subarrays. The first subarray would have two dictionaries containing bob and chris since they're both part of location 3. The second subarray would contain jane, since she is in location 50. What's my best bet in Cocoa populate this data structure? A hash table in C would probably do the trick, but I'd rather use the classes available in Cocoa.

Thanks and please let me know if I need to further clarify.

+2  A: 

And NSDictionary is a hash table.

wisequark
+3  A: 

The following code works: (edit: added my initialization code)

NSArray * arrayOfRecords = [NSArray arrayWithObjects:

    [NSDictionary dictionaryWithObjectsAndKeys:
     @"bob", @"name",
      [NSNumber numberWithInt:3], @"location",  nil],

    [NSDictionary dictionaryWithObjectsAndKeys:
     @"jane", @"name",
      [NSNumber numberWithInt:50], @"location",  nil],

    [NSDictionary dictionaryWithObjectsAndKeys:
     @"chris", @"name",
      [NSNumber numberWithInt:3], @"location",  nil],

    nil];

NSMutableDictionary * sections = [NSMutableDictionary dictionary];

for (NSDictionary * record in arrayOfRecords)
{
    id key = [record valueForKey:@"location"];
    NSMutableArray * rows = [sections objectForKey:key];

    if (rows == nil)
    {
        [sections setObject:[NSMutableArray arrayWithObject:record] forKey:key];
    }
    else
    {
        [rows addObject:record];
    }
}

NSArray * sortedKeys = [[sections allKeys] sortedArrayUsingSelector:@selector(compare:)];
NSArray * sortedSections = [sections objectsForKeys:sortedKeys notFoundMarker:@""];

NSLog(@"%@", sortedSections);
e.James
Hey James, that's currently crashing with the message: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFDictionary setObject:forKey:]: attempt to insert nil key'
I now added in the code I used to initialize arrayOfRecords. This compiles and runs for me.
e.James
A: 

In Cocoa, it's best to use model objects rather than primitive collections, especially when using Bindings. The dictionaries should certainly be model object, and you may want to turn your inner arrays into model objects as well. (The outer array should stay an array.)

Cocoa Touch doesn't have Bindings, but I find (in Cocoa, as I don't program my iPhone) that model objects make things easier to think about and work with. I recommend you make model objects anyway.

(“Model” refers to Cocoa's “Model-View-Controller” pattern, in which Cocoa provides view and controller objects and you provide the model.)

Peter Hosey
What constitutes a model object? A home-grown objective-c class that does not rely on anything in the 'NS' arena?
e.James
No. A model object models the user's data; it represents something the user is creating, editing, or otherwise manipulating. http://developer.apple.com/documentation/Cocoa/Conceptual/ModelObjects/
Peter Hosey
A: 

can someone pls tell me where i am gng wrong

  • (NSString *)getContacts { ABAddressBookRef addressbook = ABAddressBookCreate(); NSArray *allPeople = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressbook); CFIndex nPeople = ABAddressBookGetPersonCount(addressbook); NSMutableArray *data = [[NSMutableArray alloc] init];

    for (int i=0;i < nPeople;i++) { ABRecordRef ref = [allPeople objectAtIndex:i]; NSString *fname = (NSString *)ABRecordCopyValue(ref, kABPersonFirstNameProperty); NSString *lname = (NSString *)ABRecordCopyValue(ref, kABPersonLastNameProperty); ABMultiValueRef phoneNumbers = ABRecordCopyValue(ref, kABPersonPhoneProperty); NSString *phoneNumber = (NSString *)ABMultiValueCopyValueAtIndex(phoneNumbers, 0); NSArray *contactArray = [[NSArray alloc] initWithObjects:fname, lname, phoneNumber, nil]; [data addObject:contactArray];

    NSMutableDictionary * sections = [NSMutableDictionary dictionary];

    for (NSDictionary * record in allPeople) { id key = [record valueForKey:@"location"]; NSMutableArray * rows = [sections objectForKey:key];

    if (rows == nil) { [sections setObject:[NSMutableArray arrayWithObject:record] forKey:key]; } else { [rows addObject:record]; } }

mayank
To start, you didn't start each line with a tab or four spaces, so your code became a jumbled mess. Moreover, it looks like what you wrote is a new question, not an answer to this question, so you should ask it as a separate question using the “Ask Question” link up top. (Don't forget to describe in your question what actually happens with this code, and what you wanted it to do.)
Peter Hosey