Sort UITableView into sections by date from Array of events
ios, json, nsarray, objective-c, uitableview
Solution
First group all your events - you'll have to take care of variable scoping (I'm using days and groupedEvents locally but you'll have to declare those as ivars/properties)
NSMutableArray *days = [NSMutableArray array];
NSMutableDictionary *groupedEvents = [NSMutableDictionary dictionary];
- (void)groupEventsIntoDays
{
for (CalendarModel *event in _events)
{
NSString *dato = [[event.time objectAtIndex:0] startTime];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSzzz";
NSDate *gmtDate = [formatter dateFromString: dato];
if (![days containsObject:gmtDate])
{
[days addObject:gmtDate];
[groupedEvents setObject:[NSMutableArray arrayWithObject:event] forKey:gmtDate];
}
else
{
[((NSMutableArray*)[groupedEvents objectForKey:gmtDate]) addObject:event];
}
}
days = [[days sortedArrayUsingSelector:@selector(compare:)] mutableCopy];
}
Section headers:
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0,0,tableView.frame.size.width, 30)];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:header.bounds];
[header addSubview:headerLabel];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"dd-MM-yyyy HH:mm";
NSString *dateAsString = [formatter stringFromDate:[days objectAtIndex:section]];
[headerLabel setText:dateAsString];
return header;
}
I only touched the first two lines in your cellForRow - you can modify the rest as needed for display/formatting:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDate *date = [days objectAtIndex:indexPath.section];
CalendarModel *event = [((NSMutableArray*)[groupedEvents objectForKey:date]) objectAtIndex:indexPath.row];
NSString *dato = [[event.time objectAtIndex:0] startTime];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSzzz";
NSDate *gmtDate = [formatter dateFromString: dato];
formatter.dateFormat = @"dd-MM-yyyy HH:mm";
dato = [formatter stringFromDate:gmtDate];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SportCell" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:@"%@",
event.title
];
cell.detailTextLabel.text = dato;
return cell;
}
Problem
I've retrieved data from 2 different shared Google Calendars, and stored the data in an array. I need to sort the data into a sectioned UITableView, sorted by date. Heres my code: CalendarModel.h ``` #import "JSONModel.h" #import "Time.h" @interface CalendarModel : JSONModel @property (strong, nonatomic) NSString* title; @property (strong, nonatomic) NSArray<Time>* time; @end ``` CalendarModel.m ``` #import "CalendarModel.h" @implementation CalendarModel +(JSONKeyMapper*)keyMapper { return [[JSONKeyMapper alloc] initWithDictionary:@{ @"gd$when": @"time", @"title.$t": @"title", }]; } @end ``` Time.h ``` #import "JSONModel.h" @protocol Time @end @interface Time : JSONModel @property (strong, nonatomic) NSString* startTime; @property (strong, nonatomic) NSString* endTime; @end ``` Time.m does nothing, as it's handled by JSONModel SportsViewController.m ``` #import "SportsViewController.h" #import "JSONModelLib.h" #import "CalendarModel.h" #import "Time.h" #import "JSONValueTransformer.h" @interface SportsViewController () @property (strong, nonatomic) NSMutableArray *events; @property (strong, nonatomic) NSArray *music; - (NSDate *)dateAtBeginningOfDayForDate:(NSDate *)inputDate; - (NSDate *)dateByAddingYears:(NSInteger)numberOfYears toDate:(NSDate *)inputDate; @end @implementation SportsViewController - (id)initWithStyle:(UITableViewStyle)style { self = [super initWithStyle:style]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; //make HTTP call NSString* searchCall = [NSString stringWithFormat:@"http://www.google.com/calendar/feeds/kao1d80fd2u5kh7268caop11o4%%40group.calendar.google.com/public/full?alt=json"]; NSString* searchCall2 = [NSString stringWithFormat:@"http://www.google.com/calendar/feeds/3qag5m8iad46mtvsnnqbtrcjjg%%40group.calendar.google.com/public/full?alt=json"]; [JSONHTTPClient getJSONFromURLWithString: searchCall completion:^(NSDictionary *json, JSONModelError *err) { //got JSON back NSLog(@"Got Sports JSON from web: %@", json); if (err) { [[[UIAlertView alloc] initWithTitle:@"Error" message:[err localizedDescription] delegate:nil cancelButtonTitle:@"Close" otherButtonTitles: nil] show]; return; } //initialize the models _events = [CalendarModel arrayOfModelsFromDictionaries: json[@"feed"][@"entry"] ]; if (_events) NSLog(@"Loaded successfully sports models"); //show the Events [_events addObjectsFromArray:_music]; NSLog(@"%@", _events); [self.tableView reloadData]; }]; [JSONHTTPClient getJSONFromURLWithString: searchCall2 completion:^(NSDictionary *json2, JSONModelError *err2) { //got JSON back NSLog(@"Got Music JSON from web: %@", json2); if (err2) { [[[UIAlertView alloc] initWithTitle:@"Error" message:[err2 localizedDescription] delegate:nil cancelButtonTitle:@"Close" otherButtonTitles: nil] show]; return; } //initialize the models _music = [CalendarModel arrayOfModelsFromDictionaries: json2[@"feed"][@"entry"] ]; if (_music) NSLog(@"Loaded successfully music models"); [_events addObjectsFromArray:_music]; //show the Events [self.tableView reloadData]; }]; //[events addObjectsFromArray:music]; [self.tableView reloadData]; } ; -(void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - table methods -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return _events.count; } -(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { CalendarModel* event = _events[indexPath.row]; NSString *dato = [[event.time objectAtIndex:0] startTime]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSzzz"; NSDate *gmtDate = [formatter dateFromString: dato]; formatter.dateFormat = @"dd-MM-yyyy HH:mm"; dato = [formatter stringFromDate:gmtDate]; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SportCell" forIndexPath:indexPath]; cell.textLabel.text = [NSString stringWithFormat:@"%@", event.title ]; cell.detailTextLabel.text = dato; return cell; } @end ``` So basically all the data i need sorted resides in the _events array. I just do not get how i sort it by date into sections. The reason why startTime and endTime are NSStrings is that, that's what i am returned by the call to the shared calendar on Google