TableView not populating after first drilldown - iphone

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.. :)

Related

Plist to UITableView

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..

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:)]];

Navigation application with UIWebView and UITableView

I'm trying to create an application with a UITableView and when selection a row going to another view that containing a UIWebView that will load some website(passing in the row). but i still got this log :
Unknown scheme, doing nothing:
My code is below :
// RootViewController.h
#import <UIKit/UIKit.h>
#interface RootViewController : UITableViewController {
NSArray *books;
NSArray *sites;
NSArray *contacts;
}
// RootViewController.m
#import "RootViewController.h"
#import "SitesViewController.h"
#implementation RootViewController
- (void)viewDidLoad
{
// Setting the main screen title
self.title = #"Main App Screen";
// Retreiving data from the plist file
NSString *file = [[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
NSDictionary *dict = [[[NSDictionary alloc] initWithContentsOfFile:file] autorelease];
sites = [[NSArray alloc] initWithArray:[dict objectForKey:#"Sites"]];
contacts = [[NSArray alloc] initWithArray:[dict objectForKey:#"Contacts"]];
books = [[NSArray alloc] initWithArray:[dict objectForKey:#"Books"]];
[super viewDidLoad];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// We have 3 sections
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Returning the number of rows
return numberOfrows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Returning each cell
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
// section title
return title;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Handling sites section
if (indexPath.section == 0) {
SitesViewController *sitesViewController = [[SitesViewController alloc] initWithNibName:#"SitesViewController" bundle:nil];
// We want to load some data here
sitesViewController.websiteUrl = [sites objectAtIndex:indexPath.row];
// Load this view
[self.navigationController pushViewController:sitesViewController animated:YES];
// Release it
[sitesViewController release];
}
}
// SitesViewController.h
#import <UIKit/UIKit.h>
#interface SitesViewController : UIViewController {
IBOutlet UIWebView *website;
NSString *websiteUrl;
}
#property (nonatomic, retain) IBOutlet UIWebView *website;
#property (nonatomic, retain) NSString *websiteUrl;
#end
// SitesViewController.m
#import "SitesViewController.h"
#implementation SitesViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//[website setDelegate:self];
// Do any additional setup after loading the view from its nib.
NSURL *url = [[NSURL alloc] initWithString:websiteUrl];
[website loadRequest:[NSURLRequest requestWithURL:url]];
[url release];
}
....
#end
As requested the Data.plist file contain this data :
<?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>Sites</key>
<array>
<string>www.freebsd.com</string>
<string>www.kernel.org</string>
<string>www.developer.apple.com</string>
<string>www.github.com</string>
</array>
<key>Contacts</key>
<array>
<string>user#apple.com</string>
<string>user#kernel.org</string>
<string>user#gmail.com</string>
</array>
<key>Books</key>
<array>
<string>book1</string>
<string>book2</string>
<string>book3</string>
</array>
</dict>
</plist>
Thanks for the help.
You will need to add http:// to those urls. They aren't automatically prepended with it.

sectioned UITableView sourced from a pList

I'm having trouble finding a easy to understand tutorial on having a sectioned UITableView which gets its data from a pList file.
Things im having trouble with, is how to properly structure the pList file to cater for 2 different sections.
The root of the plist should be an array. The array should contain two dictionaries (your sections). The dictionaries will contain two keys: one for section title and one for the rows in the section.
Assuming you read your plist into an NSArray* sections, you can return the section, row count, section title and cell titles using the code below.
Your plist file would look like this:
<?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>Title</key>
<string>Section1</string>
<key>Rows</key>
<array>
<string>Section1 Item1</string>
<string>Section1 Item2</string>
</array>
</dict>
<dict>
<key>Title</key>
<string>Section2</string>
<key>Rows</key>
<array>
<string>Section2 Item1</string>
<string>Section2 Item2</string>
</array>
</dict>
</array>
</plist>
#import "RootViewController.h"
#interface RootViewController ()
#property (copy, nonatomic) NSArray* tableData;
#end
#implementation RootViewController
#synthesize tableData;
- (void) dealloc
{
self.tableData = nil;
[super dealloc];
}
- (void) viewDidLoad
{
[super viewDidLoad];
self.tableData = [NSArray arrayWithContentsOfFile: [[NSBundle mainBundle] pathForResource: #"Table" ofType: #"plist"]];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
{
return [tableData count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
return [[[tableData objectAtIndex: section] objectForKey: #"Rows"] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
{
return [[tableData objectAtIndex: section] objectForKey: #"Title"];
}
- (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 = [[[tableData objectAtIndex: indexPath.section] objectForKey: #"Rows"] objectAtIndex: indexPath.row];
return cell;
}
#end

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