3

I have an array of dictionaries in an iOS .plist structured similar to the following:

<plist version="1.0">
<array>
<dict>
    <key>name</key>
    <string>Afghanistan</string>
    <key>government</key>
    <string>Islamic Republic</string>
    <key>population</key>
    <integer>29121286
    </integer>
</dict>
<dict>
    <key>name</key>
    <string>Albania</string>
    <key>government</key>
    <string>Emerging Democracy</string>
    <key>population</key>
    <integer>2986952</integer>
</dict>

I am trying to load the <key>name</key> from each dictionary into an NSTableViewCell then display them all alphabetically in an NSTableView similar to the Contacts App in iOS.

Below are my ViewControllers .h and .m. The sort is working, but I am not able to load the results into the TableViewCells?

FirstViewController.h

#import <UIKit/UIKit.h>

@interface FirstViewController : UIViewController  <UITableViewDelegate,UITableViewDataSource>

{   
NSArray *sortedCountries;       
}

@property (nonatomic, retain) NSArray *sortedCountries;

@end

FirstViewController.m

#import "FirstViewController.h"

@implementation FirstViewController

@synthesize sortedCountries;



-(void)viewDidLoad  {

NSString *path = [[NSBundle mainBundle] pathForResource:@"countries"ofType:@"plist"];   
NSArray *countries = [NSArray arrayWithContentsOfFile:path];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES] autorelease];
NSArray *sortedCountries = [[countries sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];

}

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}

-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {

return 2;   
}

-(UITableViewCell *)tableView:(UITableView *)tableView
        cellForRowAtIndexPath:(NSIndexPath *)indexPath {

NSDictionary *country = [sortedCountries objectAtIndex:indexPath.row];
    NSString *countryName = [country objectForKey:@"name"];

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                   reuseIdentifier:CellIdentifier] autorelease];

}

cell.textLabel.text = countryName;
return cell;        
} 

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

}

- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;

}


- (void)dealloc {

[sortedCountries release];

[super dealloc];
}

@end

EDIT: Another question related to this here.

Community
  • 1
  • 1
mozzer
  • 241
  • 1
  • 6
  • 15

4 Answers4

5

Add an ivar to your view controller's @interface in the header file:

@interface MyViewController : UITableViewController
{
    ...
    NSArray *sortedCountries;
}

Add this code (to read and sort the plist by country name) to your view controller's initWith... method:

NSArray *countries = [NSArray arrayWithContentsOfFile: pathToPlist];
// Now the array holds NSDictionaries, sort 'em:
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES] autorelease];
sortedCountries = [[countries sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];

Then use the following snippet to extract the values:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *country = [sortedCountries objectAtIndex:indexPath.row];
    NSString *countryName = [country objectForKey:@"name"];
    NSString *governmentType = [country objectForKey:@"government"];
    NSSInteger population = [[country objectForKey:@"population"] integerValue];
    // ... do something with countryName, governmentType, population
}

Don't forget to release sortedCountries:

- (void)dealloc
{
    ...
    [sortedCountries release];
    [super dealloc];
}
Costique
  • 23,712
  • 4
  • 76
  • 79
  • Thanks. I put the first part of your code in -(void)ViewDidLoad..or should it be in -(id)initWithNibName....? Either way I get a message that sortedCountries is an 'unused variable.' I put a 'retain' at end of the NSArray *sorted... statement. Is that the correct place? – mozzer Feb 01 '11 at 20:27
  • I revised my answer to explain this too. Please re-read it from the beginning. – Costique Feb 01 '11 at 20:43
  • Thanks very much - I updated my code above which reflects your suggestions and it seems to work! – mozzer Feb 02 '11 at 03:21
  • @mozzer, consider accepting the answer if it did help. Improving your ratio of accepted answers generally increases the number of quality answers to your questions. – Costique Feb 02 '11 at 06:22
  • @Costique Thanks..I meant to accept answer after last comment. One more question..I could not figure out a way to put the sorting algorithm in an initWith method in my View Controller..so I put it in ViewDidLoad... it works, but scrolls very slowly as the sort gets called each time. Is there a way to put the code into an initWith method? I tried it in initWithNibName to no avail.. – mozzer Feb 02 '11 at 20:03
  • @mozzer If your view controller is loaded from a nib, you should put the code in `initWithCode:` instead. Anyway, `viewDidLoad` gets called only when the view gets loaded, so the performance problem is unrelated to sorting. Did you run your app through Instruments? – Costique Feb 02 '11 at 20:50
  • I reposted this as new question ( appended to end of original question above )if you are curious...it has to do with the ivar for SortedCountries...I seemingly couldn't get the retain to work in there.. My performance issue arose when I put the sort in the method that fills in the TableViewCells.Thanks for your perseverance! – mozzer Feb 02 '11 at 21:06
  • @mozzer, your mistake is putting NSArray* before `sortedCountries = ...` because that makes the expression a declaration of a _local_ variable. Without "NSArray *" the expression would be using the instance variable (ivar) declared in the class's @interface. – Costique Feb 03 '11 at 05:52
  • @Costique Thanks again...Also -- the performance issue I was seeing as you said had nothing to do with the sorting...I had forgotten to take out a series of NSLogs - and when those where called - it degraded the speed of the drawing in the Simulator... – mozzer Feb 03 '11 at 11:47
2

Create an NSArray for your file:


NSArray *iOSPlist = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"iOS" ofType:@"plist"]];
then in this method write after if (cell == nil){

}:


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cell.textLabel.text = [[iOSPlist objectAtIndex:indexPath.row] objectForKey:@"name"];
}

and don't forget to return [iOSPlist count] in the - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section method;

Skullhouseapps
  • 498
  • 1
  • 7
  • 14
1

Here is an example pulling the version number out of the info.plist. Use something similar to pull out your name key ( objectForKey:@"name")

NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:@"Info.plist"];
plist = [[NSDictionary dictionaryWithContentsOfFile:finalPath] retain]; 
NSString* version = [plist objectForKey:@"CFBundleVersion"];
Tyler Zale
  • 634
  • 1
  • 7
  • 23
1

Here's a StackOverflow question on working with data in plists. The answers get quite detailed.

Parse Plist (NSString) into NSDictionary

Community
  • 1
  • 1
macserv
  • 3,546
  • 1
  • 26
  • 36