Plist to UITableView - iphone

I am trying to populate a UITableView with information from a plist file. I don't know where I am going wrong. Please check the images for my requirement and the code above to find where I am wrong
I need to populate above image in UITableView in such way that array a, b, c should come in the section field. Its coming right in below. But I am unable to populate data
please check where I am wrong.
.
.
#synthesize mySections //array
#synthesize myData //dictionary
- (void)viewDidLoad
{
[super viewDidLoad];
//LOADING THE PLIST FILE
//Create a string representing the file path
NSString *plistPath = [bundle pathForResource:#"yourFilename" ofType:#"plist"];
//Load the file in a dictionnary
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.myData = dict;
//SORTING THE DICTIONARY
NSArray *dicoArray = [[self.myData allKeys] sortedArrayUsingComparator:^(id firstObject, id secondObject) {
return [((NSString *)firstObject) compare:((NSString *)secondObject) options: NSCaseInsensitiveSearch];
}];
self.mySections = dicoArray;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//Return the number of sections.
return [self.mySections count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSString *key = [self.mySections objectAtIndex:section];
NSArray *dataInSection = [self.myData objectForKey:key];
return [dataInSection count];
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *key = [self.mySections objectAtIndex:section];
return [NSString stringWithFormat:#"%#", key];
}
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return self.mySections;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [self.mySections objectAtIndex:section];
NSDictionary *Dic=self.myData;
NSArray *dataForSection = [self.myData objectForKey:Dic.allKeys];
cell.textLabel.text = [dataForSection objectAtIndex:row];
return cell;
}
some code of plist is:-
<plist version="1.0">
<dict>
<key>a</key>
<array>
<dict>
<key>Beta_Carot_(µg)</key>
<string>0.06</string>
<key>Cholestrl_(mg)</key>
<string>215</string>
<key>fdgdfg</key>
<string>dfgdfg</string>
</dict>
</array>
<key>b</key>
<array>
<dict>
<key>Alpha_Carot_(µg)</key>
<string>0</string>
<key>gdfg</key>
<string>fdgdfg</string>
</dict>
</array>
<key>c</key>
<array>
<dict>
<key>Alpha_Carot_(µg)</key>
<string>0</string>
<key>Ash_(g)</key>
<string>0</string>
<key>Beta_Caro</key>
<string>193</string>
<key>Choline_Tot_ (mg)</key>
<string>22.3</string>
<key>dgd</key>
<string>dgdf</string>
</dict>
</array>
</dict>
</plist>

You need to get to count the number of elements in the right data structure when determining the number of rows in each section. So in - tableView: numberOfRowsInSection: you need to have
NSArray *dataInSection = [[self.myData objectForKey:key] objectAtIndex:0];
return [dataInSection count];
There is also a problem in - tableView: cellForRowAtIndexPath:. You create the correct key to get the data for your section in *key but then you instead use Dic.allKeys as a key to retrieve data from self.myData. So you are sending in a whole array as the key when you set *dataForSection.
So change these lines:
NSString *key = [self.mySections objectAtIndex:section];
NSDictionary *Dic=self.myData;
NSArray *dataForSection = [self.myData objectForKey:Dic.allKeys];
cell.textLabel.text = [dataForSection objectAtIndex:row];
To:
NSString *key = [self.mySections objectAtIndex:section];
NSDictionary *dataForSection = [[self.myData objectForKey:key] objectAtIndex:0];
cell.textLabel.text = [[dataForSection allKeys] objectAtIndex:row];

I think you're not drilling far enough down your data hierarchy. In numberOfRowsInSection: you're getting the value for the key in the root level dictionary: Looks like this is always an NSArray with only a single item: A dictionary. You probably want something like
...
NSDictionary *dataInSection = [[self.myData objectForKey:key] objectAtIndex:0];
return [dataInSection count];
...

According to me you are doing some mistake in table fetch data from plist
plz try this
- (void)viewDidLoad
{
[super viewDidLoad];
//LOADING THE PLIST FILE
//Create a string representing the file path
NSString *plistPath = [bundle pathForResource:#"yourFilename" ofType:#"plist"];
NSMutableArray *listArray=[NSMutableArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"yourFilename" ofType:#"plist"]];
self.sections = [[NSMutableDictionary alloc] init];
}
Then set your data according to your need from plist data come as an array, then dict may be help this information you..

Related

Display Plist into UITableview

I want to display Plist to the UITableView .By my below code I can display one key values that is list of states. but i want to display all the values of three tables.
- (id)readPlist:(NSString *)fileName
{
NSData *plistData;
NSString *error;
NSPropertyListFormat format;
id plist;
NSString *localizedPath = [[NSBundle mainBundle] pathForResource:fileName ofType:#"plist"];
plistData = [NSData dataWithContentsOfFile:localizedPath];
plist = [NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if (!plist) {
NSLog(#"Error reading plist from file '%s', error = '%s'", [localizedPath UTF8String], [error UTF8String]);
}
return plist;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[[self readPlist:#"sample"] objectForKey:#"ListOfStates"] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [[[self readPlist:#"sample"] objectForKey:#"ListOfStates"] objectAtIndex:indexPath.row];
return cell;}
MY output comes only listofkeystates values
is it also possible to display key name with values
Maybe use table sections...
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
NSDictionary* dict = [self readPlist:#"sample"];
return dict.allKeys.count;
}
-(NSString*) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSDictionary* dict = [self readPlist:#"sample"];
return [dict.allKeys objectAtIndex:section];
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSDictionary* dict = [self readPlist:#"sample"];
NSString* key = [dict.allKeys objectAtIndex:section];
return [[dict valueForKey:key] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary* dict = [self readPlist:#"sample"];
NSString* key = [dict.allKeys objectAtIndex:indexPath.section];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [[dict objectForKey:key] objectAtIndex:indexPath.row];
return cell;
}
just try to get data in NSDictionary and NSArray and then use it in UITableView
NSString *file = [[NSBundle mainBundle] pathForResource:#"sample" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:file];
and use tableValue with its name like bellow...
NSArray *array = [dict objectForKey:#"ListOfStates"];
NSLog(#"%#", array);
i hope this help you..
EDIT : Corrected some typo mistakes
The idea
Loading plist in a dictonary
optional : sort it (!)
create the array of data for each section
create the array of section
Then implement the following things
viewDid load -> load the plist file in a dictionary, create an array of the sections and a dictionary of the data
numberOfSectionsInTableView -> the number of sections. In your case the number of keys
numberOfRowsInSection -> the number of rows of each section
titleForHeaderInSection -> for each section, the title of the section
cellForRowAtIndexPath -> the data of all row
sectionIndexTitlesForTableView -> the array that holds all you sections names. In your case all the keys
assuming you have a property called mySections and a property called myData
also assuming you use storyboard with standard cell with recycle identifier "Cell"
#synthesize mySections
#synthesize myData
- (void)viewDidLoad
{
[super viewDidLoad];
//LOADING THE PLIST FILE
//Create a string representing the file path
NSString *plistPath = [bundle pathForResource:#"yourFilename" ofType:#"plist"];
//Load the file in a dictionnary
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.myData = dict;
//SORTING THE DICTIONARY
NSArray *dicoArray = [[self.myData allKeys] sortedArrayUsingComparator:^(id firstObject, id secondObject) {
return [((NSString *)firstObject) compare:((NSString *)secondObject) options: NSCaseInsensitiveSearch];
}];
self.mySections = dicoArray;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//Return the number of sections.
return [self.mySections count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSString *key = [self.mySections objectAtIndex:section];
NSArray *dataInSection = [self.myData objectForKey:key];
return [dataInSection count];
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *key = [self.mySections objectAtIndex:section];
return [NSString stringWithFormat:#"%#", key];
}
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return self.mySections;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [self.mySections objectAtIndex:section];
NSArray *dataForSection = [self.myData objectForKey:key];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = [dataForSection objectAtIndex:row];
return cell;
}

Ordering UITableView Sections Loaded From pList

I have a sectioned UITableView being populated by data from a pList. The root of the pList is a dictionary, each key of this dictionary is loaded into an array, which is used to define the section headings (and presumably order).
Currently my sections appear in the table in a random order, I would like to order them as they appear in the pList, or at least fake it by ordering the sections alphabetically.
I understand that dictionaries have no order, which is why the output does not reflect the pList order, but I would prefer not to change the root to an array as it requires me to rewrite chunks of my app, plus Xcode 4 seems to prefer you using a dictionary as the root. Of course if changing the pList structure is the best method, I'll go with that.
pList sample:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Section A</key>
<array>
<dict>
<key>Details</key>
<string>Details Here...</string>
<key>Image</key>
<string>X.png</string>
<key>Name</key>
<string>Person X</string>
</dict>
<dict>
<key>Details</key>
<string>Details Here...</string>
<key>Image</key>
<string>Y.png</string>
<key>Name</key>
<string>Person Y</string>
</dict>
</array>
<key>Section B</key>
<array>
<dict>
<key>Details</key>
<string>Details Here...</string>
<key>Image</key>
<string>Z.png</string>
<key>Name</key>
<string>Person Z</string>
</dict>
</array>
</dict>
Code within 'TableViewController.m':
- (void)viewDidLoad {
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"Team" ofType:#"plist"];
NSDictionary *tempDict = [[NSDictionary alloc] initWithContentsOfFile:path];
self.teamDictionary = tempDict;
[tempDict release];
NSArray *tempArray = [[NSArray alloc] init];
self.teamArray = tempArray;
[tempArray release];
self.teamArray = [self.teamDictionary allKeys];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self.teamArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self.teamDictionary valueForKey:[self.teamArray objectAtIndex:section]] count];
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
// this is here because I am altering the appearance of the header text
UIView* customView = [[[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, tableView.bounds.size.width, 44.0)] autorelease];
UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
// some custom formatting stuff has been removed from here...
headerLabel.text = [self.teamArray objectAtIndex:section];
[customView addSubview:headerLabel];
[headerLabel release];
return customView;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [teamArray objectAtIndex:section];
NSArray *teamMember = [teamDictionary objectForKey:key];
static NSString *SectionsTableIdentifier = #"SectionsTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SectionsTableIdentifier] autorelease];
}
// Configure the cell...
NSDictionary *name = [teamMember objectAtIndex:row];
cell.textLabel.text = [name objectForKey:#"Name"];
}
I can think of two options:
Use an array as the root of your plist. Each item in the array would be a dictionary, with two keys: name/title and items. Name/title would be a string and items would be an array.
Keep your plist as is, order the keys alphabetically:
NSArray *sortedKeys = [[dict allkeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)]];

TableView not populating after first drilldown

I have a Sectioned Tableview sourced from a pList which I want to drill down into children sub views. My only problem is I'm stuck on getting it to populate after first drill down (Entree is the only one with content), "Description" and "Title".
pList
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>Rows</key>
<array>
<dict>
<key>Title</key>
<string>Entree</string>
<key>Children</key>
<array>
<dict>
<key>Title</key>
<string>Garlic Bread</string>
<key>Description</key>
<string>Cottage loaf smeared with garlic butter and herbs</string>
<key>Price</key>
<string>8.0</string>
</dict>
<dict>
<key>Title</key>
<string>Bruschetta</string>
<key>Description</key>
<string>Veggies n shit on toast</string>
<key>Price</key>
<string>9.0</string>
</dict>
</array>
</dict>
<dict>
<key>Title</key>
<string>Mains</string>
</dict>
<dict>
<key>Title</key>
<string>Dessert</string>
</dict>
<dict>
<key>Title</key>
<string>Sides</string>
</dict>
</array>
<key>Title</key>
<string>Eat</string>
</dict>
<dict>
<key>Title</key>
<string>Drink</string>
<key>Rows</key>
<array>
<dict>
<key>Title</key>
<string>Red</string>
</dict>
</array>
</dict>
</array>
</plist>
MenuViewController.h
#import <UIKit/UIKit.h>
#interface MenuViewController : UITableViewController {
NSArray *tableDataSource;
NSString *CurrentTitle;
NSInteger CurrentLevel;
}
#property (nonatomic, retain) NSArray *tableDataSource;
#property (nonatomic, retain) NSString *CurrentTitle;
#property (nonatomic, readwrite) NSInteger CurrentLevel;
#end
MenuViewController.m
#import "MenuViewController.h"
#implementation MenuViewController
#synthesize tableDataSource;
#synthesize CurrentLevel, CurrentTitle;
- (void)viewDidLoad
{
[super viewDidLoad];
if(CurrentLevel == 0) {
self.tableDataSource = [NSArray arrayWithContentsOfFile: [[NSBundle mainBundle] pathForResource: #"MenuData" ofType: #"plist"]];
self.navigationItem.title = #"Menu";
}
else
self.navigationItem.title = CurrentTitle;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
#warning Potentially incomplete method implementation.
return [tableDataSource count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
#warning Incomplete method implementation.
return [[[tableDataSource objectAtIndex: section]
objectForKey: #"Rows"] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[tableDataSource objectAtIndex: section]
objectForKey: #"Title"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *dictionary = [[[self.tableDataSource objectAtIndex: indexPath.section] objectForKey: #"Rows"] objectAtIndex: indexPath.row];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
*//The problem is right here, im just stuck on how to access this property correctly
**cell.textLabel.text = [dictionary objectForKey:#"Title"];***
// Configure the cell...
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
NSDictionary *dictionary = [[[self.tableDataSource objectAtIndex: indexPath.section] objectForKey: #"Rows"] objectAtIndex: indexPath.row];
//Get the children of the present item.
NSArray *Children = [dictionary objectForKey:#"Children"];
if([Children count] == 0) {
MenuDetailViewController *mdvController = [[MenuDetailViewController alloc] initWithNibName:#"MenuDetailView" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:mdvController animated:YES];
[mdvController release];
}
else {
//Prepare to tableview.
MenuViewController *mvController = [[MenuViewController alloc] initWithNibName:#"MenuViewController" bundle:[NSBundle mainBundle]];
//Increment the Current View
mvController.CurrentLevel += 1;
//Set the title;
mvController.CurrentTitle = [dictionary objectForKey:#"Title"];
//Push the new table view on the stack
[self.navigationController pushViewController:mvController animated:YES];
mvController.tableDataSource = Children;
[mvController release];
}
}
#end
You can drill data in recursive manner.
For root view controller cell selection method
you have to modify your code as
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if(self.currentLevel=0)
return [tableDataSource count];
else
return 1;//You require only one section in later levels
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(self.currentLevel=0)
return [[[tableDataSource objectAtIndex: section] objectForKey: #"Rows"] count];
else
return [tableDataSource count];// Number of children
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if(self.currentLevel=0)
return [[tableDataSource objectAtIndex: section] objectForKey: #"Title"];
else
return self.title;//Or your custom title
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *dictionary = nil;
if(self.currentLevel=0)
dictionary= [[[self.tableDataSource objectAtIndex: indexPath.section] objectForKey: #"Rows"] objectAtIndex: indexPath.row];
else
dictionary = [self.tableDataSource objectAtIndex: indexPath.row];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = [dictionary objectForKey:#"Title"];
// Configure the cell...
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(self.currentLevel=0)
dictionary= [[[self.tableDataSource objectAtIndex: indexPath.section] objectForKey: #"Rows"] objectAtIndex: indexPath.row];
else
dictionary = [self.tableDataSource objectAtIndex: indexPath.row];
if([dictionary objectForKey:#"Children"]!=nil){
//Drill down only if you have child
//Now drilling down logic
id Object = [dictionary objectForKey:#"Children"];
NSString * title = [dictionary objectForKey:#"Title"];
if([object isKindOfClass:[NSArray class]) {
NSArray * dataSource = (NSArray *)object;
MenuViewController * viewController = [[MenuViewController alloc] initWithNibName:#"YourNibName" bundleNameOrNil:nil];
viewController.title = title;
viewController.tableDataSource = dataSource;
viewController.currentLevel = self.currentLevel+1;
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
} else if([object isKindOfClass:[NSDictionary class]) {
//Only one child in the form of dictionary
//Initialize your detail view controller and push to nav stack
YourDetailViewController * viewController = [[YourDetailViewController alloc] initWithNibName:#"YourNibName" bundleNameOrNil:nil];
viewController.data = (NSDictionary*)object;//Pass the view data(price etc)
viewController.currentLevel = self.currentLevel+1;
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
} else {
//Error drilling down is not possible
}
}
}
Hope this will sort out your drilling problem.. :)

Configuring a UITableViewCell object with unique image and text

Given a .plist similar to :
<plist version="1.0">
<array>
<dict>
<key>name</key>
<string>Afghanistan</string>
<key>government</key>
<string>Islamic Republic</string>
<key>population</key>
<integer>0</integer>
<key>image</key>
<string>/Flags/afghanistan.png</string>
</dict>
<dict>
<key>name</key>
<string>Albania</string>
<key>government</key>
<string>Emerging Democracy</string>
<key>population</key>
<integer>0</integer>
<key>image</key>
<string>/Flags/albania.png</string>
</dict>
.... etc.
And ViewController.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];
self.sortedCountries = [countries sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]];
}
-(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];
}
NSDictionary *item = (NSDictionary *)[sortedCountries objectAtIndex:indexPath.row];
NSString *path = [[NSBundle mainBundle] pathForResource:[item objectForKey:#"image"] ofType:#"png"];
UIImage *theImage = [UIImage imageWithContentsOfFile:path];
cell.imageView.image = theImage;
cell.textLabel.text = countryName;
return cell;
}
This puts countryName in ascending alphabetical order as expeted in the UITableView Cells. What is not working is cell.imageView.image.
It puts afghanistan.png in the first UITableViewCell as expected. The Cells that follow also receive afghanistan.png as well however. ( The second cell should receive 'albania.png', etc ). How can I fix this UIImageView problem?
Use imageNamed instead.
cell.imageView.image = [UIImage imageNamed:[item objectForKey:#"image"]];
You should use
[item objectForKey:#"image"] in stead of
[item objectForKey:#"imageKey"]
(as the .plist uses <key>image</key>).

Displaying .plist key values alphabetically in an UITableView

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.
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];
}
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;
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"];
Here's a StackOverflow question on working with data in plists. The answers get quite detailed.
Parse Plist (NSString) into NSDictionary