Filter Tableview - ios

How to filter tableview based on a picker value?
I have the following NSMutableArray:
[0]:Object 1 (name1, October)
[1]:Object 2 (name2, November)
[2]:Object 3 (name3, March)
[3]:Object 4 (name4, April)
[4]:Object 5 (name5, April)
The table view displays the value of these objects.
and I have a picker with month values (January, February,... etc)
so based on the user selection of picker value, the table view should display values for example if I choose month April, only these values object 3 and 4 should appear.
Solution code, thanks to Fennelouski: (just thought I'd put it here In case someone needs it)
NSMutableArray *array;
NSMutableArray *filteredArray;
int monthInt;
NSString *monthString;
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
Titles *object1 = [[Titles alloc]init];
[object1 setTitle:#"Title1"];
[object1 setMonth:#"10"];
Titles *object2 = [[Titles alloc]init];
object2.title = #"Title2";
object2.month = #"10";
Titles *object3 = [[Titles alloc]init];
object3.title = #"Title3";
object3.month = #"4";
array = [[NSMutableArray alloc]init];
filteredArray = [[NSMutableArray alloc]init];
[array addObject:object1];
[array addObject:object2];
[array addObject:object3];
pickerData = #[#"Jan", #"Feb", #"March", #"April", #"May", #"June", #"July", #"Aug", #"Sept", #"October", #"Nov", #"Dec"];
NSDate *currentDate = [NSDate date];
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:currentDate];
monthInt= [components month];
monthString = [NSString stringWithFormat:#"%li",(long)monthInt];
for (Titles *item in array)
{
if([item.month isEqualToString:monthString])
{
[filteredArray addObject:item];
}
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [filteredArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
Titles *titles = filteredArray[indexPath.row];
cell.textLabel.text = titles.title;
cell.imageView.image = [UIImage imageNamed:#"totoro.jpg"];
NSLog(#"Cell is %#", [array objectAtIndex:indexPath.row]);
return cell;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (int)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
// The number of rows of data
- (int)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return pickerData.count;
}
// The data to return for the row and component (column) that's being passed in
- (NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return pickerData[row];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSLog(#"Row: %li", (long)row);
monthString = [NSString stringWithFormat:#"%li",row+1];
[filteredArray removeAllObjects];
for (Titles *item in array)
{
if([item.month isEqualToString:monthString])
{
[filteredArray addObject:item];
}
}
[self.tableview reloadData];
}

It seems like you're following the design pattern of having your table view represent information stored in a separate data structure. That's good and makes filtering much easier.
Fortunately, you don't have to really do much with the table view to filter the results. All you need to do is filter the data structure that your table view is reading from and then update the table view.
I'd recommend adding an array in between your mutable array and the table view.
Something like this should work well for you
NSMutableArray *filteredObjects = [NSMutableArray new];
for (MYObjectClass *object in myMutableArray) {
if ([object.stringProperty isEqualToString:#"Filter"]) {
[filteredObjects addObject:object];
}
}
Then have your table view reference filteredObjects rather than the array you're using that has all of your data.

Related

Add Alphabetical Headers to UITableView with a sorted array

I'm sorting my array by last name alphabetically. I'd like to separate this into sections with the appropriate header above each section (A, B, C, etc.).
Here's what I've tried below:
// Here is where I refresh the data and sort it based on last name
- (void)refreshData {
[[PCMSSessionManager sharedSession] refreshPCMSDataWithCompletion:^(BOOL success, NSString *errorMessage, id resultObject) {
if (success) {
NSLog(#"yay!");
self.membersArray = [[PCMSSessionManager sharedSession] memberArr];
// Let's sort the array
self.sortedArray = [self.membersArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first = [(PCMSMember*)a lastName];
NSString *second = [(PCMSMember*)b lastName];
return [first compare:second];
}];
[self.tableView reloadData];
} else {
NSLog(#"boooo!!!!");
}
}];
}
- (NSDictionary *)indexedMembers
{
NSMutableDictionary *indexedContacts = [NSMutableDictionary new];
for (PCMSMember *member in self.sortedArray)
{
NSString *sortString = member.lastName;
NSString *sortLetter = [sortString substringToIndex:1];
/* see if that letter already exists as an index */
BOOL foundKey = NO;
for (NSString *key in [indexedContacts allKeys])
{
if ([key isEqualToString:sortLetter])
{
foundKey = YES;
}
}
NSMutableArray *valueArray;
if (foundKey)
{
valueArray = [((NSArray *)indexedContacts[sortLetter]) mutableCopy];
}
else
{
valueArray = [NSMutableArray new];
}
[valueArray addObject:member];
indexedContacts[sortLetter] = [valueArray copy];
}
return [indexedContacts copy];
}
// Here's my table data
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[[self indexedMembers] allKeys] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSDictionary *indexedContacts = [self indexedMembers];
NSArray *myKeys = [indexedContacts allKeys];
NSString *key = myKeys[section];
return [((NSArray *)[self indexedMembers][key]) count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"cellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// Configure the cell...
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (self.isPhysician == YES) {
NSString *key = [[self indexedMembers] allKeys][indexPath.section];
PCMSMember *currentMember = ((NSArray *)[self indexedMembers][key])[indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", currentMember.firstName, currentMember.lastName];
}
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[self indexedMembers] allKeys][section];
}
UPDATE:
This is getting me closer to what I want.
The data is loading, it's being grouped properly and the headers are showing.
But it's not in alphabetical order.
How can I improve this code to show alphabetically?
It's showing in alphabetical order in my console, just not in the app.
The NSMutableDictionary is unordered by definition. It is not the natural choice if you rely on the order of the stored objects. I suggest you to use NSMutableArray instead. To store the tableview data for each section you can use this mini class
#interface MembersWithSameInitial : NSObject
#property (strong) NSString* initial;
#property (strong) NSMutableArray<PCMSMember*>* members;
#end
#implementation MembersWithSameInitial
#end
After you have sorted the members, all the data for the tableview can be produced with this before tableView reload.
NSMutableArray<MembersWithSameInitial*>* groupedMembers = [[NSMutableArray alloc] init];
for (PCMSMember* member in sortedArray) {
NSString* inicial = [member.lastName substringToIndex:1];
MembersWithSameInitial* last = [groupedMembers lastObject];
if (last && [last.initial isEqualToString:inicial]) {
[last.members addObject:member];
} else {
MembersWithSameInitial* newGroup = [[MembersWithSameInitial alloc] init];
newGroup.initial = inicial;
newGroup.members = [[NSMutableArray alloc] initWithObjects:member, nil];
[groupedMembers addObject:newGroup];
}
}
Since the structure of groupedMembers fits to a grouped tableView, the dataSource methods will have trivial implementations. Assuming, that you have stored groupedMembers in a property.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.groupedMembers.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.groupedMembers[section].members.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//...
PCMSMember *currentMember = self.groupedMembers[indexPath.section].members[indexPath.row];
//...
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return groupedMembers[section].initial;
}
Suggestion:
Create two properties
#property NSMutableArray *keys; // for the letters in alphabetical order
#property NSMutableDictionary *indexedContacts; // same as your implementation.
In the method refreshData call the method to create the data source and then reload the table view on the main thread.
Actually you don't need the properties memberArray and sortedArray anymore. The sorted array is passed to the method to create the data source.
- (void)refreshData {
[[PCMSSessionManager sharedSession] refreshPCMSDataWithCompletion:^(BOOL success, NSString *errorMessage, id resultObject) {
if (success) {
NSLog(#"yay!");
self.membersArray = [[PCMSSessionManager sharedSession] memberArr];
// Let's sort the array
NSArray *sortedArray = [self.membersArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first = [(PCMSMember*)a lastName];
NSString *second = [(PCMSMember*)b lastName];
return [first compare:second];
}];
[self indexMembers:sortedArray];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
} else {
NSLog(#"boooo!!!!");
}
}];
}
The method indexMembers initializes the properties keys and indexedContacts and creates the data source.
- (void)indexMembers:(NSArray *)sortedMembers
{
self.keys = [[NSMutableArray alloc] init];
self.indexedContacts = [[NSMutableDictionary alloc] init];
for (PCMSMember *member in sortedMembers)
{
NSString *sortString = member.lastName;
NSString *sortLetter = [sortString substringToIndex:1];
/* see if that letter already exists as an index */
NSArray *keyArray = self.indexedContacts[sortLetter];
NSMutableArray *valueArray;
if (keyArray) {
// array for key exists, use it
valueArray = [keyArray mutableCopy];
} else {
// array for key does not exist, create a new one
valueArray = [NSMutableArray new];
// and add the letter to keys
[self.keys addObject:sortLetter];
}
[valueArray addObject:member];
self.indexedContacts[sortLetter] = [valueArray copy];
}
}
numberOfSectionsInTableView returns the number of keys
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.keys.count;
}
numberOfRowsInSection gets the appropriate array for the given section and returns the number of items.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *letter = self.keys[section];
NSArray *memberArray = self.indexedContacts[letter];
return memberArray.count;
}
In cellForRowAtIndexPath use the method dequeueReusableCellWithIdentifier: forIndexPath: to get always a valid cell. Then like in numberOfRowsInSection get the actual member array and populate the label.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"cellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// Configure the cell...
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if (self.isPhysician == YES) {
NSString *letter = self.keys[indexPath.section];
NSArray *memberArray = self.indexedContacts[letter];
PCMSMember *currentMember = memberArray[indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", currentMember.firstName, currentMember.lastName];
}
return cell;
}
titleForHeaderInSection simply returns the letter for the section
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return self.keys[section];
}
You're calling indexedMembers too much. This is very expensive.
I couldn't test the code, maybe there is a self or something else missing but you get an impression of the workflow.

Adding section and index list with custom cell, searchdisplaycontroller

I have created a UITableView with custom cell & stored name,no,pincode in to these cell.
Here is my Code for array:-
for (int i =0; i<[tempArr count]; i++)
{
NSString *rawData = [tempArr objectAtIndex:i];
if (rawData !=nil)
{
Persons *newPerson = [[Persons alloc]init];
NSArray *data = [rawData componentsSeparatedByString:#"\t"];
newPerson.name = [NSString stringWithFormat:#"%#",[data objectAtIndex:0]];
newPerson.no = [[data objectAtIndex:1] integerValue];
newPerson.pincode = [[data objectAtIndex:2] integerValue];
[allPersons addObject:newPerson];
}
}
Here is my Customcell.h
#interface Customcell : UITableViewCell
#property(weak) Persons* person;
#end
UITableView Datasrouce method:-
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Customcell *cell = [tblStations dequeueReusableCellWithIdentifier:#"personCell"];
if (tableView == self.searchDisplayController.searchResultsTableView)
{
cell.person = filteredContentList[indexPath.row];
[cell.textLabel setText:cell.person.name];
}
else
{
cell.person = allPersons[indexPath.row];
[cell.textLabel setText:cell.person.name];
}
return cell;
}
How do i create Section & index list for all names from A to Z & give title by cell.textLabel.text?
I am following This Tutorial but it has static keys & names added to NSDictionary,NSArray.
In my example i do not know how many names starting with same letter can come in the array. i am also using UISearchDisplayController for search person name.
I want to add number of sections & title for those sections by names that is in the array or cell.textLabel.text dynamically.
i do not know about UISearchDisplayController that these sections & index list will be displaying in UISearchDisplayController so i do not want these sections & index list while searching.
You need to spend a little more time trying to make your questions more clear.
Include a custom implementation of the necessary UITableView data source and delegate methods...
NOTE my assumption that your variable allPersons is an NSMutableArray.
NOTE these do not include for your search results data sets!
Return an NSInteger for the number of sections in your UITableView...
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSSet *setData = nil;
NSInteger integerData = 0;
setData = [NSSet setWithArray:allPersons];
integerData = [setData count];
return integerData;
}
UPDATE
Return an NSString for section header titles...
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSOrderedSet *setData = nil;
NSString *stringData = nil;
setData = [NSOrderedSet orderedSetWithArray:allPersons];
stringData = [[setData allObjects] componentsJoinedByString:#" "];
return stringData;
}
...plus others if I have the time...

PFQueryTableViewController loading for 5 minutes

I followed this tutorial here https://parse.com/questions/using-pfquerytableviewcontroller-for-uitableview-sections and was able to create a beautiful table with sections, but it takes forever to load! Well, not forever, 5 minutes to be exact. My table in parse has 587 rows in it and it takes 5 minutes to load all of the objects into sections. The first few minutes shows the "Loading..." on the blank view, then there is an empty tableview, and finally all of the objects load. Is there a reason something like this is taking so long? I can't have my users wait 5 minutes for something to load. This tableview is displayed during the register process. It is a list of schools and the new user must select which school they are from. The sections organize the schools based on location, and there are about 30 sections. Any suggestions for getting this to load faster?
Here is the code for the SchoolFinderViewController.m file
#import "SchoolFinderViewController.h"
#interface SchoolFinderViewController ()
#property (nonatomic, retain) NSMutableDictionary *sections;
#property (nonatomic, retain) NSMutableDictionary *sectionToRegionMap;
#end
#implementation SchoolFinderViewController
#synthesize sections = _sections;
#synthesize sectionToRegionMap = _sectionToRegionMap;
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
self.parseClassName = #"School";
self.textKey = #"Name";
self.pullToRefreshEnabled = NO;
self.paginationEnabled = YES;
self.objectsPerPage = 600;
self.sections = [NSMutableDictionary dictionary];
self.sectionToRegionMap = [NSMutableDictionary dictionary];
}
return self;
}
-(void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Schools";
}
#pragma mark - PFQueryTableViewController
- (void)objectsDidLoad:(NSError *)error {
[super objectsDidLoad:error];
// This method is called every time objects are loaded from Parse via the PFQuery
NSLog(#"Count in objectsDidLoad: %lu", (unsigned long)[self.objects count]);
[self.sections removeAllObjects];
[self.sectionToRegionMap removeAllObjects];
NSInteger section = 0;
NSInteger rowIndex = 0;
int i = 0;
for (PFObject *object in self.objects) {
PFObject *obj = [object objectForKey:#"region"];
[obj fetchIfNeeded];
NSLog(#"School %#", [object objectForKey:#"Name"]);
NSString *Region = [obj objectForKey:#"name"];
NSLog(#"Reg: %#", Region);
NSMutableArray *objectsInSection = [self.sections objectForKey:Region];
if (!objectsInSection) {
objectsInSection = [NSMutableArray array];
NSLog(#"Is this called? %d", i);
// this is the first time we see this Region - increment the section index
[self.sectionToRegionMap setObject:Region forKey:[NSNumber numberWithInt:section++]];
}
[objectsInSection addObject:[NSNumber numberWithInt:rowIndex++]];
[self.sections setObject:objectsInSection forKey:Region];
}
NSLog(#"Finally done...");
}
- (PFQuery *)queryForTable {
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
// If no objects are loaded in memory, we look to the cache first to fill the table
// and then subsequently do a query against the network.
if (self.objects.count == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
// Order by name
[query orderByAscending:#"Name"];
return query;
}
- (PFObject *)objectAtIndexPath:(NSIndexPath *)indexPath {
NSString *Region = [self RegionForSection:indexPath.section];
NSArray *rowIndecesInSection = [self.sections objectForKey:Region];
NSNumber *rowIndex = [rowIndecesInSection objectAtIndex:indexPath.row];
return [self.objects objectAtIndex:[rowIndex intValue]];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.sections.allKeys.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSString *Region = [self RegionForSection:section];
NSArray *rowIndecesInSection = [self.sections objectForKey:Region];
return rowIndecesInSection.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *Region = [self RegionForSection:section];
return Region;
}
#pragma mark - UITableViewDelegate
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSLog(#"CellFor %ld", (long)indexPath.row);
cell.textLabel.text = [object objectForKey:#"Name"];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
PFObject *selectedObject = [self objectAtIndexPath:indexPath];
}
#pragma mark - ()
- (NSString *)RegionForSection:(NSInteger)section {
return [self.sectionToRegionMap objectForKey:[NSNumber numberWithInt:section]];
}
Yeah, you're not going to be able to make this fast enough as-is... The client should not have to download every object first, and scrolling lists with 500+ items are not a good user experience. Perhaps you should have an initial screen where they pick some subset, and then they can query a smaller set of data on the next screen. What you're currently using as a section might be a good candidate.

Creating multiple sections in table view in iphone

I am creating such table view which has not specified the number of sections (that means number of sections should be specified dynamically in its respected delegate i.e. - -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView) or not specified the rows in each sections (That means the number of rows in each sections also should be specified by dynamically in its respected delegates i.e.- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section) as below image in which the section of table specifies the month with year and each section can have any number of rows. The image is -
as above image january 2014 section has 4 rows and december 2013 has 2 rows. I would like to create such type of table view. Is it possible ? if it is possible than please provide proper way or any example or any link through which I can achieve it. Thanks in advanced.
Please Use below Code. Hope It will be useful to u.
in .h file defile
int i
in viewdidload method of .m file
arrData = [NSMutableArray array];
int temp = 1;
for (i = 0; i < 5; i++) {
NSMutableArray * arrIndexData = [NSMutableArray array];
for (int j = 0; j<=i; j++,temp++) {
[arrIndexData addObject:[NSString stringWithFormat:#"%d",temp]];
}
[arrData addObject:arrIndexData];
}
Now in numberOfSectionsInTableView
return i;
in numberOfRowsInSection
return [arrData count];
in cellForRowAtIndexPath
static NSString *CellIdentifier = #"Cell";
CustomCell * cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
[cell reloadTableWithArrData:[arrData objectAtIndex:indexPath.row]];
return cell;
I hope, this ll help u..
#Jekil , Just set Your DateFormatter to MMMM yyyy ,
Check my updated Answer
As all suggests use Array of Dictionary in Dictionary put two object one for Title (Nsstring) and second is NSArray ( dict for cell detail),
I have implemented One method for that in my app,
NOTE: Use Your Key Values for your data.
Use Following code for Arranging Array,
-(NSMutableArray*)arrangeSection:(NSMutableArray *)source
{
NSDateFormatter *_formatter=[[NSDateFormatter alloc]init];
[_formatter setLocale:[NSLocale currentLocale]];
[_formatter setDateFormat:#"MMMM yyyy"];
NSMutableArray *arrayMain=[NSMutableArray array];
for (int i=0; i<source.count; i++){
NSDictionary *dict=source[i];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:[[dict objectForKey:#"StartDate"]doubleValue]];
NSString *mm=[_formatter stringFromDate:date];
NSMutableDictionary *secDict=[NSMutableDictionary dictionary];
NSMutableArray *secArray=[NSMutableArray array];
if (i==0){
[secDict setObject:mm forKey:#"Month"];
[secArray addObject:dict];
[secDict setObject:secArray forKey:#"Data"];
[arrayMain addObject:secDict];
}
else{
BOOL flg=NO;
for (NSDictionary *dict2 in arrayMain){
if([[dict2 objectForKey:#"Month"]isEqualToString:mm]){
flg=YES;
[[dict2 objectForKey:#"Data"]addObject:dict];
break;
}
}
if (!flg){
[secDict setObject:mm forKey:#"Month"];
[secArray addObject:dict];
[secDict setObject:secArray forKey:#"Data"];
[arrayMain addObject:secDict];
}
}
}
return arrayMain;
}
Now in tableview Methods use as,
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return arrayEvents.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[arrayEvents[section]objectForKey:#"Data"]count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
...
NSDictionary *aDict = [arrayEvents objectAtIndex:indexPath.section];
NSDictionary *maindict=[[aDict objectForKey:#"Data"]objectAtIndex:indexPath.row];
...
}

Using NSSortDescriptor to sort UITableview title with setDateFomat:#"dd.MMMM-EEEE

I have a title in UITableView with different dates with the formate of dd.MMMM-EEEE. How can I sort them according to time from old to new? Should I use NSSortDescriptor?
Here is my code:
#synthesize managedObjectContext, pictureListData;
#synthesize scroll;
-(IBAction)scrolldown:(id)sender{
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *today = [NSDate date];
NSInteger index = NSNotFound;
if ([pictureListData containsObject:today]) {
index = [pictureListData indexOfObject:today];
}
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionNone
animated:YES];
}
-(void)viewDidLoad{
NSSortDescriptor * sortDesc = [[NSSortDescriptor alloc] initWithKey:#"self" ascending:YES];
[pictureListData sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]];
[self.tableView reloadData];
}
- (void)viewWillAppear:(BOOL)animated
{
// Repopulate the array with new table data
[self readDataForTable];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"dd.MMMM - EEEE"];
NSDate *today = [NSDate date];
[pictureListData enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
Pictures *picture = (Pictures *)obj;
NSDate *date = [dateFormatter dateFromString:picture.title];
NSDateComponents *components = [cal components:NSDayCalendarUnit
fromDate:date
toDate:today
options:0];
if ([components day]==0) {
*stop = TRUE;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop
animated:YES];
}
}];
}
// When the view reappears, read new data for table
// Grab data for table - this will be used whenever the list appears or reappears after an add/edit
- (void)readDataForTable
{
// Grab the data
pictureListData = [CoreDataHelper getObjectsForEntity:#"Pictures" withSortKey:#"title" andSortAscending:YES andContext:managedObjectContext];
// Force table refresh
[self.tableView reloadData];
}
#pragma mark - Actions
// Button to log out of app (dismiss the modal view!)
#pragma mark - Segue methods
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get a reference to our detail view
PictureListDetail *pld = (PictureListDetail *)[segue destinationViewController];
// Pass the managed object context to the destination view controller
pld.managedObjectContext = managedObjectContext;
// If we are editing a picture we need to pass some stuff, so check the segue title first
if ([[segue identifier] isEqualToString:#"EditPicture"])
{
// Get the row we selected to view
NSInteger selectedIndex = [[self.tableView indexPathForSelectedRow] row];
// Pass the picture object from the table that we want to view
pld.currentPicture = [pictureListData objectAtIndex:selectedIndex];
}
}
#pragma mark - Table view data source
// Return the number of sections in the table
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
// Return the number of rows in the section (the amount of items in our array)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [pictureListData count];
}
// Create / reuse a table cell and configure it for display
- (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];
}
// Get the core data object we need to use to populate this table cell
Pictures *currentCell = [pictureListData objectAtIndex:indexPath.row];
// Fill in the cell contents
cell.textLabel.text = [currentCell title];
cell.detailTextLabel.text = [currentCell desc];
// If a picture exists then use it
if ([currentCell smallPicture])
{
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
cell.imageView.image = [UIImage imageWithData:[currentCell smallPicture]];
}
return cell;
}
// Swipe to delete has been used. Remove the table item
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Get a reference to the table item in our data array
Pictures *itemToDelete = [self.pictureListData objectAtIndex:indexPath.row];
// Delete the item in Core Data
[self.managedObjectContext deleteObject:itemToDelete];
// Remove the item from our array
[pictureListData removeObjectAtIndex:indexPath.row];
// Commit the deletion in core data
NSError *error;
if (![self.managedObjectContext save:&error])
NSLog(#"Failed to delete picture item with error: %#", [error domain]);
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
#end
Modify your dataSource initializing method. Regular sortDescriptor is not sufficient as you need to change the dateString to date for comparison.
- (void)readDataForTable
{
// Grab the data
pictureListData = [CoreDataHelper getObjectsForEntity:#"Pictures" withSortKey:#"title" andSortAscending:YES andContext:managedObjectContext];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"dd.MMMM - EEEE"];
[pictureListData sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
Pictures *picture1 = (Pictures *)obj1;
Pictures *picture2 = (Pictures *)obj2;
NSDate *date1 = [dateFormatter dateFromString:picture1.title];
NSDate *date2 = [dateFormatter dateFromString:picture2.title];
return [date1 compare:date2];
}];
// Force table refresh
[self.tableView reloadData];
}

Resources