Sort UITableview in objective c with dates descending NSDictionary - iphone

Thank you for looking into my question here. I am trying to get uitableview sectioned by dates in descending order. I get the data from the sqllite order by datefield desc. But whatever I do the dates are displayed in ascending order. I have the following set of data that comes out of the db and in this order:
ID BookName DateRead
1 ABC 19-10-2011
2 ABZ 27-06-2011
3 ABD 28-05-2011
I would like the data to appear like the following
19-10-2011
ABC
27-06-2011
ABZ
28-05-2011
ABD
but no matter what I am trying I am getting the data returned as below:
19-10-2011
ABC
28-05-2011
ABZ
27-06-2011
ABD
Here is the complete list of code that I am using:
.h file
#import <UIKit/UIKit.h>
#interface BookHistoryViewController : UITableViewController {
NSArray *books;
NSMutableDictionary *sections;
}
#property (nonatomic,retain) NSArray *books;
#property (nonatomic,retain) NSMutableDictionary *sections;
#end
Here is my .m file
- (void)viewDidLoad {
TestAppDelegate *appDelegate = (TestAppDelegate *)[[UIApplication sharedApplication] delegate];
[Book getInitialDataToDisplay:[appDelegate getDBPath]];
self.books = [NSMutableArray arrayWithArray:appDelegate.bookArray];
self.sections = [[NSMutableDictionary alloc] init];
BOOL found;
// Loop through the books and create our keys
for (NSDictionary *book in books)
{
NSString *c = [book valueForKey:#"DateRead"];
found = NO;
for (NSString *str in [self.sections allKeys])
{
if ([str isEqualToString:c])
{
found = YES;
}
}
if (!found)
{
[self.sections setValue:[[NSMutableArray alloc] init] forKey:c];
}
}
// Loop again and sort the books into their respective keys
for (NSDictionary *book in self.books)
{
[[self.sections valueForKey:[book valueForKey:#"DateRead"]] addObject:book];
}
// Sort each section array
for (NSString *key in [self.sections allKeys])
{
[[self.sections objectForKey:key] sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"DateRead" ascending:NO]]];
}
[super viewDidLoad];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[self.sections allKeys] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [[[self.sections allKeys] sortedArrayUsingSelector:#selector(compare:)] objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:#selector(compare:)] objectAtIndex:section]] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *book = [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:#selector(compare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.text = [book valueForKey:#"title"];
return cell;
}

When you get the book in tableView:cellForRowAtIndexPath:, you first sort by section key which is the dateRead as a string, but you sort in ascending order. You probably want to sort using a descriptor like you do in viewDidLoad. In fact, why not just keep it in the correctly sorted order so that you don't have to sort each time you need a cell? The way you are doing it will cause the interface to grind to a halt pretty quickly.

Related

UITableView and alphabetical order

In my app I parse an XML file then I would like to show the entry of this file in a UITableView. I found on the web how to make section in alphabetical order (like iPhone contacts), it works fine with my app. When i tap on a row in my tableview I want to display another ViewController, in which I will find some information about the row I tapped, but I'm having some problem: when I tap on a row the variable indexPath.row refers to the section and the information in new view controller aren't right. I will post here some screenshot to show you want I'm trying to explain.
In the following pictures you can see how the app should work:
In the following pictures you can see the error of my app:
You can see that in picture 1 the name is the same and in picture 2 you can see that the name it's wrong. I guess it depend on the variable indexPath.row. I will post here the code to create and populate the tableview:
#import "TableWasteViewController.h"
#import "WasteXmlParser.h"
#import "WasteDetailViewController.h"
#interface TableWasteViewController ()
#property(nonatomic,strong)NSArray *arrayWastes;
#property(nonatomic,strong)NSMutableArray *typeOfWaste;
#property(nonatomic,strong)NSMutableArray *typeOfBin;
#property(nonatomic,strong)NSMutableArray *indexWastes;
#property(nonatomic,strong)NSMutableArray *typeOfWasteBackup;
#end
#implementation TableWasteViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
WasteXmlParser *parser = [[WasteXmlParser alloc]init];
[parser parseWasteXml];
self.arrayWastes = [[NSArray alloc]init];
self.arrayWastes = [parser.arrayWastes mutableCopy];
self.indexWastes = [[NSMutableArray alloc]init];
self.typeOfWaste = [[NSMutableArray alloc]init];
self.typeOfBin = [[NSMutableArray alloc]init];
for (int i = 0; i < [self.arrayWastes count]; i++) {
[self.typeOfWaste addObject:[[self.arrayWastes objectAtIndex:i] objectForKey:#"type"]];
[self.typeOfBin addObject:[[self.arrayWastes objectAtIndex:i]objectForKey:#"place"]];
}
for (int i = 0; i < [self.typeOfWaste count]-1; i++) {
char alphabet = [[self.typeOfWaste objectAtIndex:i] characterAtIndex:0];
NSString *uniChar = [NSString stringWithFormat:#"%c", alphabet];
if (![self.indexWastes containsObject:uniChar]) {
[self.indexWastes addObject:uniChar];
}
}
self.typeOfWasteBackup = [self.typeOfWaste mutableCopy];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.indexWastes count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [self.indexWastes objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *alphabet = [self.indexWastes objectAtIndex:section];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#",alphabet];
NSArray *wastes = [self.typeOfWaste filteredArrayUsingPredicate:predicate];
return [wastes count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UIFont *myFont = [UIFont fontWithName:#"Arial" size:14.0];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSString *alphabet = [self.indexWastes objectAtIndex:[indexPath section]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *wastes = [self.typeOfWaste filteredArrayUsingPredicate:predicate];
if ([wastes count] > 0) {
NSString *cellValue = [wastes objectAtIndex:indexPath.row];
cell.textLabel.font = myFont;
cell.textLabel.numberOfLines = 2;
cell.textLabel.text = cellValue;
}
return cell;
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return self.indexWastes;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSIndexPath *indexPath = [self.tableWaste indexPathForSelectedRow];
WasteDetailViewController *vc = segue.destinationViewController;
vc.typeOfWaste = [self.typeOfWaste objectAtIndex:indexPath.row];
vc.typeOfBin = [self.typeOfBin objectAtIndex:indexPath.row];
vc.urlPic = [self.arrayWastes[indexPath.row]objectForKey:#"imgUrl"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)backToHome:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
I hope you can help me to fix this issue. Thank you
Rows are indexed by section, i.e. the first item in each section has indexPath.row == 0. So in order to look up values in your flattened vc.typeOfWaste and vc.typeOfBin arrays, you're going to need to do something along the lines of your numberOfRowsInSection method, where you filter the flattened array by the alphabet character and then get the item of the filtered array using indexPath.row.
Overall, this approach seems rather messy, having to filter your data repeatedly. Your data structures don't map well to the problem being solved. I would recommend using the TLIndexPathTools data model TLIndexPathDataModel because it's specifically designed for tables and collection views, can organize your data into sections, and can look up items by index path. Would be happy to walk you through a refactor if you like.
It's because the arrays that you're using to pass the data to the WasteDetailViewController, which are "typeOfWaste, typeOfBin, and urlPic" aren't sorted. The sorted array is called "wastes", but it is only available within the numberOfRowsInSection and the cellForRowAtIndexPath methods. You need to be passing the data in the wastes array forward, so rather than sorting the wastes array all the time, just sort it once after you've loaded it.
Add this property:
#interface TableWasteViewController ()
#property (strong, nonatomic) NSArray *sortedWastes;
#end
Now in viewDidLoad
NSString *alphabet = [self.indexWastes objectAtIndex:section];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#",alphabet];
self.sortedWastes = [self.typeOfWaste filteredArrayUsingPredicate:predicate];
Finally, in prepareForSegue
vc.typeOfWaste = [self.sortedWastes objectAtIndex:indexPath.row];
Your problems all stem from the fact that you are displaying a sorted array, but the array that you are using to pass the data forward is the unsorted array, so the indexPath is completely useless.
Furthermore, your typeOfBin and urlPic are going to be wrong as well. You need to find some way to link all three of your arrays together, so that when you sort one, you sort them all. The method above only keeps your typeOfWaste array sorted.
I also faced this issue few days ago...u need to make one class set properties whatever you want and then add that object in one array after that u can sort array on one property then whole array will be sorted
#import <Foundation/Foundation.h>
#interface HomeFeed : NSObject
#property (nonatomic, copy) UIImage *ItemImage;
#property (nonatomic, copy) NSString *ItemTitle;
#property (nonatomic, copy) NSString *ItemDate;
#property (nonatomic, copy) NSString *ItemDescription;
#property (nonatomic, copy) NSString *ItemHours;
#property (nonatomic, copy) NSString *ItemID;
#property (nonatomic, copy) NSString *itemDetailUrl;
#property (nonatomic, copy) NSString *itemPerson;
#property (nonatomic, copy) NSString *itemThumbUrl;
#property (nonatomic, assign) int ItemDuration;
#end
#import "HomeFeed.h"
#implementation HomeFeed
#synthesize ItemTitle=_ItemTitle, ItemDate=_ItemDate, ItemImage=_ItemImage,ItemID=_ItemID,ItemDuration=_ItemDuration,ItemDescription,ItemHours=_ItemHours,itemDetailUrl,itemPerson,itemThumbUrl;
#end
NSArray*arr=[responseString JSONValue];
NSLog(#"Json Dictionary speakersss : %#",arr);
NSLog(#"Json arr count speaker : %i",arr.count);
for (int i=0; i<arr.count; i++) {
NSDictionary *dict=[[ NSDictionary alloc]init];
dict=[arr objectAtIndex:i];
HomeFeed *feed = [[HomeFeed alloc] init];
feed.ItemTitle = [NSString stringWithFormat:#"%#%#%#",[dict objectForKey:#"firstName"],#" ",[dict objectForKey:#"lastName"]];
feed.ItemDuration = [[NSString stringWithFormat:#"%#", [dict objectForKey:#"count"]] intValue];
feed.itemDetailUrl=[dict objectForKey:#"detailsUrl"];
[self.itemsDataArray addObject:feed];
[itemTitle addObject:feed.ItemTitle];
}
HomeFeed *feed = [[HomeFeed alloc] init];
NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:#"ItemTitle" ascending:YES];
[self.itemsDataArray sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SpeakersCustomCell"];
cell.selectionStyle = NO;
cell.accessoryType = NO;
HomeFeed *feed = [self.itemsDataArray objectAtIndex:indexPath.row];
UIImageView *arrow = (UIImageView *)[cell viewWithTag:3];
arrow.image = [UIImage imageNamed:#"accessory.png"];
UILabel *lblLeft = (UILabel *)[cell viewWithTag:1];
UILabel *lblRight = (UILabel *)[cell viewWithTag:2];
lblLeft.text=feed.ItemTitle;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
HomeFeed *feed=(HomeFeed*)[self.itemsDataArray objectAtIndex:indexPath.row];
self.onlinDetail.strUrl=feed.itemDetailUrl;
NSString *key = #"OrientationStringValue";
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:feed.itemDetailUrl forKey:key];
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotifSpeaker1" object:nil userInfo:dictionary];
}

Second view in UITableView will not display parsed data from JSON

I have a parsed data from JSON file. It works like a charm in the first view of my UITableView. However, it displays a blank second view when I tap on an item.
MasterView.h
#interface MasterViewController : UITableViewController
{
NSArray *json;
}
#property (nonatomic, retain) NSArray *json;
#end
MasterView.m
#import "MasterViewController.h"
#import "InformationViewController.h"
#interface MasterViewController ()
#end
#implementation MasterViewController
#synthesize json;
- (void)viewDidLoad
{
[super viewDidLoad];
NSData *jsonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://j4hm.t15.org/ios/console.php"]];
[self performSelectorOnMainThread: #selector(fetchedData:) withObject: jsonData waitUntilDone: YES];
}
- (void)fetchedData:(NSData *)responseData
{
NSError *error;
self.json = [NSJSONSerialization JSONObjectWithData: responseData options: kNilOptions error: &error];
NSLog(#"String is %#", self.json);
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [json count];
}
// Customize the appearance of table view cells.
- (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];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = [[json objectAtIndex: indexPath.row] objectForKey: #"Console"];
[cell setAccessoryType: UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
InformationViewController *informationViewController = [[InformationViewController alloc] initWithStyle:UITableViewStylePlain];
informationViewController.title = [[json objectAtIndex: indexPath.row] objectForKey: #"Console"];
informationViewController.Information = [[json objectAtIndex: indexPath.row] objectForKey: #"Model"];
NSLog(#"String is %#", informationViewController.Information);
[self.navigationController pushViewController: informationViewController animated:YES];
}
InformationView.h
#interface InformationViewController : UITableViewController
#property (nonatomic, strong) NSArray * Information;
#end
InformationView.m
#interface InformationViewController ()
#end
#implementation InformationViewController
#synthesize Information;
- (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];
}
// Configure the cell...
cell.textLabel.text = [[Information objectAtIndex: indexPath.row] objectForKey: #"Model"];
[cell setAccessoryType: UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
Here i Posted Another Answer Just Because i don't want to Generate Confusion.
The Project Code : http://www.cogzentappz.com/demo/iostutorial/TestJson.zip
instead of passing the Selected Value, Pass the Whole Array through NSUsedDefaults And Retrive them Using Following Code.
- (void)fetchedData:(NSData *)responseData
{
NSError *error;
self.json = [NSJSONSerialization JSONObjectWithData: responseData options: kNilOptions error: &error];
NSLog(#"String is %#", self.json);
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arrayObj = [[NSMutableArray alloc] init];
for(int i = 0 ; i<[self.json count] ; i++) {
[arrayObj addObject:[json objectAtIndex:i]]];
}
[standardDefaults setObject:arrayObj forKey:#"longArray"];
[arrayObj release];
}
In the Next View you can Retrive the data Using the Below method.
in ViewDidLoad of informationViewcontroller use This
//reading
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
NSArray *arrayObj = [standardDefaults objectForKey:#"longArray"];
for(int i = 0 ; i<[arrayObj count] ; i++) {
NSLog(#"String is %#",[arrayObj objectAtIndex:i]);
}
As per Your Link The Json Output is like Below :
NSArray-->NSDictionary-->NSArray-->NSDictionary-->NSArray-->NSDictionary
Go to the link : http://json.bloople.net and Post all your json output and Hit enter.
So you have to get the values According to that format.
for(int i = 0 ; i<[self.json count] ; i++) {
NSArray *info_Array=[[self.json objectAtIndex:i ]valueForKey:#"Information"];
NSLog(#"info_Array is %#", info_Array);
for(int j = 0 ; j<[info_Array count] ; j++)
{
NSLog(#"Model is %#", [[info_Array objectAtIndex:j ]valueForKey:#"Model"]);
NSArray *title_Array=[[info_Array objectAtIndex:j ]valueForKey:#"Title"];
for(int k = 0 ; k<[title_Array count] ; k++)
{
NSLog(#"Game is %#", [[title_Array objectAtIndex:k ]valueForKey:#"Game"]);
NSLog(#"Publisher is %#", [[title_Array objectAtIndex:k ]valueForKey:#"Publisher"]);
}
}
NSString *Console_string= [[dataArray objectAtIndex:i ]valueForKey:#"Console"];
NSLog(#"String is %#", Console_string);
}
NSString *Console_string= [[self.Json objectAtIndex:i ]valueForKey:#"Console"];
NSLog(#"String is %#", Console_string);
}
I think you have to reloadData after you fetch your data. Right now, you specify that the NSArrray *json is empty, since the count returns 0. Thus, you prohibit the table view from being filled. Call [tableView reloadData]; after you fetch your data.
Change your code of MaterView.m with this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
InformationViewController *informationViewController = [[InformationViewController alloc] initWithStyle:UITableViewStylePlain];
informationViewController.title = [[json objectAtIndex: indexPath.row] objectForKey: #"Console"];
informationViewController.Information = [[json objectAtIndex: indexPath.row] objectForKey: #"Model"];
NSLog(#"String is %#", informationViewController.Information);
[self.navigationController pushViewController: informationViewController animated:YES];
}
Hope it helps you...

UITableView: use object from dictionary as title on detail view

I have the following code to make a table from string turned into a dictionary:
- (void)viewDidLoad {
[super viewDidLoad];
testArray = [[NSArray alloc] init];
NSString *testString = #"Sam|26,Hannah|22,Adam|30,Carlie|32";
testArray = [testString componentsSeparatedByString:#","];
dict = [NSMutableDictionary dictionary];
for (NSString *s in testArray) {
testArray2 = [s componentsSeparatedByString:#"|"];
[dict setObject:[testArray2 objectAtIndex:1] forKey:[testArray2 objectAtIndex:0]];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
if (testArray.count >indexPath.row) {
cell.textLabel.text = [[dict allKeys] objectAtIndex:[indexPath row]];
cell.detailTextLabel.text = [dict objectForKey:cell.textLabel.text];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
What I would like is for the selected row title to be set as the title on my detail view.
I tried with:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.detailController.title = [[dict allKeys] objectAtIndex:[indexPath row]];
[self.navigationController pushViewController:self.detailController animated:YES];
}
But I get an "EXC_BAD_ACCESS" error.
It works fine if I use #"1" as title, it's just something with my dictionary call that's wrong, I assume.
Make dict a retained dictionary instead of an autoreleased one.
I.E. declare it maybe like this:
dict = [[NSMutableDictionary alloc] initWithCapacity: [testArray count]];
in your viewDidLoad method. Make sure to release it when viewDidUnload is called.
Also, make sure of the number of keys in your dict before calling:
self.detailController.title = [[dict allKeys] objectAtIndex:[indexPath row]];
So, I would do:
if(dict && ([[dict allKeys] count] > [indexPath row])
{
self.detailController.title =
[[dict allKeys] objectAtIndex:[indexPath row]];
} else {
self.detailController.title = #"Here's a problem";
}
Did you implement these UITableView delegate methods ? All these are needed. Also can you post more detailed StackTrace.
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [resultSet count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 280.0;
}

UITableView abcd list indexing

I need to implement the abcd list indexing in the below table view right side.when i am clicking on a/b/c etc table view need to show the entries according to that for sorting like iphone contacts .may i know what are all
the changes i need for it.is need to create sections for that?please any one explain me
any solution.
I have an class named as "myClass" which contains the properties iD, name and imageURL.
image url holds the photolibrary alasset url.
myClass.h
#interface myClass: NSObject {
NSInteger iD;
NSString *name;
NSString *imageURL;
}
#property (nonatomic, assign) NSInteger iD;
#property (nonatomic, assign) NSString *name;
#property (nonatomic, assign) NSString *imageURL;
myClass.m
#implementation myClass
#synthesize iD;
#synthesize name;
#synthesize imageURL;
#end
So I added 50 image details with iD, name, imageURL as myClass objects in to an NSMutableArray named as *BundleImagesArray *
i displayed it in a table view. my code is:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
//getting all image details with iD,name,imageURL as **myClass** objects
BundleImagesArray = [staticDynamicHandler getImageFromBundle];
int count = [BundleImagesArray count];
for (int i = 0; i<count; i++) {
//this array for easy scrolling after first time the table is loaded.
[imageCollectionArrays addObject:[NSNull null]];
}
return count;
}
cellForRowAtIndexPath
- (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];
}
//removing all the subviews
if ([cell.contentView subviews]) {
for (UIView *subview in [cell.contentView subviews]) {
[subview removeFromSuperview];
}
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell setAccessoryType:UITableViewCellAccessoryNone];
myClass *temp = [BundleImagesArray objectAtIndex:indexPath.row];
//adding image view
UIImageView *importMediaSaveImage=[[[UIImageView alloc] init] autorelease];
importMediaSaveImage.frame=CGRectMake(0, 0, 200,135 );
[cell.contentView addSubview:importMediaSaveImage];
//adding image label
UILabel *sceneLabel=[[[UILabel alloc] initWithFrame:CGRectMake(220,0,200,135)] autorelease];
sceneLabel.font = [UIFont boldSystemFontOfSize:16.0];
sceneLabel.textColor=[UIColor blackColor];
[cell.contentView addSubview:sceneLabel];
sceneLabel.text = temp.name;
if([imageCollectionArrays objectAtIndex:indexPath.row] == [NSNull null]){
//getting photlibrary image thumbnail as NSDAta
NSData *myData = [self photolibImageThumbNailData::temp.imageURL]
importMediaSaveImage.image =[UIImage imageWithData:myData ];
[imageCollectionArrays replaceObjectAtIndex:indexPath.row withObject:importMediaSaveImage.image];
} else {
importMediaSaveImage.image = [imageCollectionArrays objectAtIndex:indexPath.row];
}
temp = nil;
return cell
}
*Note:*
i done it using the following way
1.Number of sections-
inside this we are getting the label array and then calling the method countArrayWords whihc will count the words and
the alphabets starting from a particular word.
2.Title for headerin section-
Used for gettting the headers for the sections.Currently we are not using this methd as it will not look good when we are having
no data on the table view.
3.number of rows in section-
in this we are calling the method countArrayWords if the sectio=0.
4.cell for row at index path-
this is the method in which we are calculating a variable known as h through which we are using to bind the images to the table
view.
However the Tableview performence is too slow with 1000 images
An easy way to handle this is to create 2 arrays, one of sections, and another of section titles. You can then populate these from your sorted array of MyClass'es in your init method (initWithObjects: , say)
- (id) initWithObjects: (NSArray *) myObjectsArray
{
self = [super initWithNibName: <your-nib-name> bundle: nil];
if (self) {
self.sections = [NSMutableArray array];
self.sectionTitles = [NSMutableArray array];
for (MyClass * object in self.myObjectsArray) {
NSMutableArray * section = [self.sections lastObject];
if (!section || ![[[[section lastObject] name] substringToIndex: 1] isEqualToString: [object.name substringToIndex: 1]]) {
// Create a new section on change of first character
[self.sections addObject: [NSMutableArray array]];
[self.sectionTitles addObject: [object.name substringToIndex: 1]];
}
[[self.sections lastObject] addObject: object];
}
}
return self;
}
Then your datasource methods are
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.sections count];
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self.sections objectAtIndex: section] count];
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Create cell
MYClass * object = [[self.sections objectAtIndex: indexPath.section] objectAtIndex: indexPath.row];
//Configure cell
return cell;
}
- (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tableView
{
return self.sectionTitles;
}

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