Calendar Dates in TableView with Infinite Scrolling - ios

I am trying to implement to show the calendar dates in TableViewCell. I am able to achieved the filled with current year. But As soon I hit the bottom of the table I need to populate next year and if I hit at top of TableView then previous year should be populated.
Pasting code which I have implemented.
- (void)fillDatesWithCalendarUnit:(NSCalendarUnit)unit withDate:(NSDate*)date
{
NSDate *today = date;
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *beginning;
NSTimeInterval length;
[calendar rangeOfUnit:unit startDate:&beginning interval:&length forDate:today];
NSDate *end = [beginning dateByAddingTimeInterval:length-1];
[self fillDatesFromDate:beginning toDate:end];
}
- (void)fillDatesFromDate:(NSDate *)fromDate toDate:(NSDate *)toDate
{
NSAssert([fromDate compare:toDate] == NSOrderedAscending, #"toDate must be after fromDate");
NSDateComponents *days = [[NSDateComponents alloc] init];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSInteger dayCount = 0;
while(YES){
[days setDay:dayCount++];
NSDate *date = [calendar dateByAddingComponents:days toDate:fromDate options:0];
if([date compare:toDate] == NSOrderedDescending) break;
[_dates addObject:date];
}
[self.tableView reloadData]; //_dates mutableArray
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dates.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AgendaCustomCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"Cell"];
cell.date.text = [NSString stringWithFormat:#"%#",_dates[indexPath.row]];
if (indexPath.row == _dates.count-1) {
NSLog(#"load more");
NSDate *tomorrow = [NSDate dateWithTimeInterval:(48*60*60) sinceDate:_dates[indexPath.row]];
NSLog(#"last daye - %# ,tomorrow - %#",_dates[indexPath.row],tomorrow);
[self fillDatesWithCalendarUnit:NSCalendarUnitYear withDate:_dates[indexPath.row]];
}
return cell;
}

I have implemented the logic for show infinite future dates on scrolling.
- (void)viewDidLoad {
[super viewDidLoad];
_dates = [NSMutableArray new];
[self fillCurrentYear];
}
- (void)fillCurrentYear
{
[self fillDatesWithCalendarUnit:NSCalendarUnitYear withDate:[NSDate new
] isLoadMore:NO];
}
pragma mark Private methods
- (void)fillDatesWithCalendarUnit:(NSCalendarUnit)unit withDate:(NSDate*)date isLoadMore:(BOOL)isBool
{
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *beginning;
NSTimeInterval length;
if (isBool) {
beginning = _dates[[_dates count]-1];
}
[calendar rangeOfUnit:unit startDate:&beginning interval:&length forDate:date];
NSDate *end = [beginning dateByAddingTimeInterval:length-1];
[self fillDatesFromDate:beginning toDate:end];
}
- (void)fillDatesFromDate:(NSDate *)fromDate toDate:(NSDate *)toDate
{
NSAssert([fromDate compare:toDate] == NSOrderedAscending, #"toDate must be after fromDate");
// NSMutableArray *dates = [[NSMutableArray alloc] init];
NSDateComponents *days = [[NSDateComponents alloc] init];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSInteger dayCount = 0;
while(YES){
[days setDay:dayCount++];
NSDate *date = [calendar dateByAddingComponents:days toDate:fromDate options:0];
if([date compare:toDate] == NSOrderedDescending) break;
[_dates addObject:date];
}
// _dates = dates;
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AgendaCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"Cell"];
cell.date.text = [NSString stringWithFormat:#"%#",_dates[indexPath.row]];
if (indexPath.row == _dates.count-1) {
NSLog(#"load more");
NSDate *tomorrow = [NSDate dateWithTimeInterval:(48*60*60) sinceDate:_dates[indexPath.row]];
NSLog(#"last daye - %# ,tomorrow - %#",_dates[indexPath.row],tomorrow);
[self fillDatesWithCalendarUnit:NSCalendarUnitYear withDate:tomorrow isLoadMore:YES];
}
return cell;
}

Related

Get a EKEvent from a array iOS

I want to get an EKEvent from an array iOS. But I have one problem. If I put my code lines in the viewDidLoad method, it works.
But if I make it in a button from a table view: (-(IBAction)button:(UiButton *)sender) it gets an EKEvent, but doesn't note the event.
Thats my code:
EKEvent *event =[eventArray objectAtIndex:0]
NSString *string = event.notes
Thats the complete code:
- (void)viewDidLoad {
selectedDate = [NSDate date];
[super viewDidLoad];
EKEventStore *store = [[EKEventStore alloc] init];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted == NO) {
UIViewController *controller = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"needAccess"];
[self.view addSubview:controller.view];
[self addChildViewController:controller];
}
}];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *start = [calendar dateBySettingHour:0 minute:0 second:0 ofDate:selectedDate options:0];
NSDate *end = [calendar dateBySettingHour:0 minute:0 second:0 ofDate:[selectedDate dateByAddingTimeInterval:60*60*24] options:0];
NSPredicate *predicate = [store predicateForEventsWithStartDate:start endDate:end calendars:nil];
eventArray = [store eventsMatchingPredicate:predicate];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [eventArray count];
}
- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [table dequeueReusableCellWithIdentifier: #"EventCell"];
EKEvent *event = [eventArray objectAtIndex:indexPath.row];
UIButton *headline = (UIButton *)[cell viewWithTag:1];
headline.layer.cornerRadius = headline.frame.size.width / 2;
headline.clipsToBounds = YES;
headline.tag = indexPath.row;
[headline addTarget:self action:#selector(headlineButton:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
-(void)headlineButton:(UIButton*)sender {
EKEvent *event = [eventArray objectAtIndex:0];
NSArray *notes = [event.notes componentsSeparatedByString:#"//"];
NSString *latitude = [notes objectAtIndex:1];
NSString *longitude = [notes objectAtIndex:2];
}
That's probably because neither the cell or the button on the cell have an EKEvent property.
Your cell is loaded from a model. The event data is likely in the model
If your button or cell needs to access event data, you have to decide how the data flows through your app. You also want to have a single source of truth for the event, so no matter what your app's state, you always are certain about details for an event, whether editing or updating or persisting or deleting or inserting an event.
These are questions you may want to tackle, so you have a really good understanding where and how you store these details, and how your cell button should access an event's note.

iOS. Table View Cell swipe hard working

I have custom table view cell. And this code for swipe-deletion:
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return reportingCellIndexPath != indexPath;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
NSInteger result = [self.messagesModel numberOfDifferentDayDatesInMessages];
return result;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSDate *sectionDate = [self.messagesModel dayDateAtNumber:section];
NSInteger rowsCount = [self.messagesModel numberOfMessagesWithDayDate:sectionDate];
return rowsCount;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger realMessageIndex = [self.messagesModel fullMessageIndexForMessageWithDayDateNumber:indexPath.section index:indexPath.row];
SDMessage *message = [self.messagesModel messageAtIndex:realMessageIndex];
// SDMessage *message = [self.messagesModel messageAtIndex:indexPath.row withDayDateAtNumber:indexPath.section];
static NSString *messageCellId = #"messageCellId";
SDMessageCell *_messageCell = [tableView dequeueReusableCellWithIdentifier:messageCellId];
if (_messageCell == nil) {
_messageCell = [[SDMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:messageCellId];
}
[_messageCell rebuildWithMessage:message];
_messageCell.delegate = self;
if ([reportingCellIndexPath isEqual:indexPath] &&
![_messageCell reportViewIsShowing]) {
[_messageCell showReportViewWithMessagesModel:self.messagesModel messageIndex:realMessageIndex];
} else if ([_messageCell reportViewIsShowing]) {
[_messageCell hideReportView];
}
return _messageCell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat result = [self tableView:tableView cellForRowAtIndexPath:indexPath].frame.size.height;
return result;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 40;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSDate *sectionDate = [self.messagesModel dayDateAtNumber:section];
if (sectionDate != nil) {
return [self sectionTitleForSectionDate:sectionDate];
} else {
return #"";
}
}
- (NSString *)sectionTitleForSectionDate:(NSDate *)date {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
NSDateComponents *dateComponents = [calendar components:
NSYearCalendarUnit |
NSMonthCalendarUnit |
NSDayCalendarUnit |
NSWeekdayCalendarUnit |
NSWeekCalendarUnit
fromDate:date];
NSDateComponents *nowComponents = [calendar components:NSYearCalendarUnit |
NSMonthCalendarUnit |
NSDayCalendarUnit |
NSWeekdayCalendarUnit |
NSWeekCalendarUnit
fromDate:now];
if (dateComponents.year == nowComponents.year &&
dateComponents.month == nowComponents.month &&
dateComponents.week == nowComponents.week) {
if (nowComponents.weekday - dateComponents.weekday < 2) {
[dateFormatter setDoesRelativeDateFormatting:YES];
} else {
[dateFormatter setDateFormat:#"EEEE"];
}
}
return [dateFormatter stringFromDate:date];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self cancelSearchField];
NSInteger realMessageIndex = [self.messagesModel fullMessageIndexForMessageWithDayDateNumber:indexPath.section index:indexPath.row];
if (indexPath.row < self.messagesModel.size && realMessageIndex > -1) {
[self.messagesModel selectMessageAtIndex:realMessageIndex];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
self.refreshBeforeShowing = NO;
[self.navigationController pushViewController:self.detailViewController animated:YES];
}
}
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSInteger realMessageIndex = [self.messagesModel fullMessageIndexForMessageWithDayDateNumber:indexPath.section index:indexPath.row];
[SDModalLoadingIndicator showLoading];
[self.messagesModel deleteMessageAtIndex:realMessageIndex success:^() {
[SDModalLoadingIndicator hideLoading];
NSString *msg = NSLocalizedString(#"Message has been deleted", nil);
[[[[iToast makeText:msg]
setDuration:iToastDurationNormal]
setGravity:iToastGravityBottom] show];
[self.tableView reloadData];
} failureCallback:^(NSString *message, NSMutableArray *validationErrors, NSError *error) {
[SDModalLoadingIndicator hideLoading];
[SDFailureHandler handleConnectFailure:message withError:error];
}];
}
}
But almost always it don't show delete button on swipe.(Sometimes button will be showing). Do somebody know why?
I've tried to debug this thing check all views by debugger, and they have only system gesture recognizers(pan, tap, long press, edge).
Also I can say that this method "tableView:canEditRowAtIndexPath:" is called each time I swipe cell but nothing happened.(In most cases)
You need to make sure you also have a commitEditingStyle delegate function setup.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle != UITableViewCellEditingStyleDelete)
return;
// perform the delete!
}
Also, remember the swipe to delete is only present when the tableView isn't being edited (in edit mode, the minus button is visible on the rows instead).
I, just forgot that my application was using side menu. So side menu was adding pan gesture on my view for closing and opening on drag event.
And I understand if you have all necessary methods implemented and delete on swipe don't work. ALWAYS try to find some gesture or element that is catching you touch event.

UITableView Population Slowness

I'm trying to make an app with a calendar being displayed and as soon as a day on the calendar (each day is a UIView with a tap gesture) is tapped, all calendar appointments for that day should be displayed in a UITableView. I've got this working, but there's a big lag between when the tap occurs and when the data is actually populated into the UITableView. Here's my code:
EKEventStore *store = [[EKEventStore alloc] init];
//Access Granted to Calendar by user
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
// Create the start date components
NSDateFormatter *startFormatter = [[NSDateFormatter alloc]init];
[startFormatter setDateFormat:#"MM/dd/yyyy hh:mm a"];
NSString *monthNumberString = [NSString stringWithFormat:#"%i", month];
NSString *startDateString = [[[[[monthNumberString stringByAppendingString:#"/"] stringByAppendingString:dLabel.text] stringByAppendingString:#"/"] stringByAppendingString:yearString] stringByAppendingString:#" 12:01 am"];
NSDate *start = [startFormatter dateFromString:startDateString];
NSLog(#"Start Date: %#", startDateString);
// Create the end date components
NSDateFormatter *endFormatter = [[NSDateFormatter alloc]init];
[endFormatter setDateFormat:#"MM/dd/yyyy hh:mm a"];
NSString *endDateString = [[[[[monthNumberString stringByAppendingString:#"/"] stringByAppendingString:dLabel.text] stringByAppendingString:#"/"] stringByAppendingString:yearString] stringByAppendingString:#" 11:59 pm"];
NSDate *end = [endFormatter dateFromString:endDateString];
NSLog(#"End Date: %#", endDateString);
// Create the predicate from the event store's instance method
NSPredicate *predicate = [store predicateForEventsWithStartDate:start
endDate:end
calendars:nil];
// Fetch all events that match the predicate
events = [store eventsMatchingPredicate:predicate];
//Sort the array
events = [events sortedArrayUsingSelector:#selector(compareStartDateWithEvent:)];
int eventCount = [events count];
NSLog(#"%i", eventCount);
for (int i=0; i<eventCount; i++) {
EKEvent *theEvent = [events objectAtIndex:i];
NSLog (#"Element %i = %#", i, theEvent.title);
}
UITableView *dayTableView = [[UITableView alloc] initWithFrame:CGRectMake(360, 0, 300, 550)
style:UITableViewStylePlain];
dayTableView.backgroundColor = lightBlueColor;
dayTableView.separatorColor = [UIColor clearColor];
dayTableView.delegate = self;
dayTableView.dataSource = self;
[super addSubview:dayTableView];
}];
UITableview Delegate Functions:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog (#"I made a section!");
return 1; //count of section
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog (#"I made %i rows!", [events count]);
return [events count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *c = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"mycell"];
EKEvent *theEvent = [events objectAtIndex:indexPath.row];
c.textLabel.text = theEvent.title;
NSLog (#"Cell %i = %#", indexPath.row, theEvent.title);
//c.textLabel.text = #"Calendar Event Goes Here";
c.textLabel.textColor = [UIColor whiteColor];
//NSLog (#"I made a cell!");
return c;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 35;
}
Any help would be greatly appreciated.
Without profiling it is difficult to say what the bottleneck of your code is. However, based on previous experience I would say that it is the lines that looks like
NSString *startDateString = [[[[[monthNumberString stringByAppendingString:#"/"] stringByAppendingString:dLabel.text] stringByAppendingString:#"/"] stringByAppendingString:yearString] stringByAppendingString:#" 12:01 am"];
At least if it is called +20000x (or something) a second. First of all it would be more convienient to write this as
NSString *startDateString = [NSString stringWithFormat:#"%#/%#/%# 12:01 am", monthNumberString, dLabel.text, yearString];
But I fear this would not speed up your program much. I would recommend going back to plain C code and use e.g. sprintf instead. You can look up the syntax of it here as well as some examples of use.
I found the answer. The problem is here:
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
the way that the event store is accessed is different on iOS6 and iOS5. Here's a link that shows the correct way of doing it:
http://fostah.com/ios/2012/09/28/ios6-event-edit.html

Have JSON data, would like to show with sections in IOS6 app

I have retrieved my events from a shared google calendar i IOS, and are displaying them in a tableview. As for right now, they're simplty shown with the event title as the title, and the eventtime as the subtitle. I'd like to use the date (eventtime) as a section header in stead, so that all events on for instance march 31st where shown in a group, with the time as a "right detail"
My code looks like this:
#interface MasterViewController () {
NSArray *events;
}
#end
#implementation MasterViewController
-(void)viewDidAppear:(BOOL)animated
{
//show loader view
//[HUD showUIBlockingIndicatorWithText:#"Fetching JSON"];
//make HTTP call
NSString* searchCall = [NSString stringWithFormat:#"http://www.google.com/calendar/feeds/kao1d80fd2u5kh7268caop11o4%%40group.calendar.google.com/public/full?alt=json"];
[JSONHTTPClient getJSONFromURLWithString: searchCall
completion:^(NSDictionary *json, JSONModelError *err) {
//got JSON back
NSLog(#"Got 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 models");
//show the videos
[self.tableView reloadData];
}];
}
;
#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];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"yyyy-MM-dd'T'HH:mm:ss.SSSzzz";
NSDate *gmtDate = [formatter dateFromString: [[event.time objectAtIndex:0] startTime]];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"%#",
event.title
];
cell.detailTextLabel.text = [formatter stringFromDate: gmtDate];
return cell;
}
#end
I have found this code online, but he doesn't get data as JSON, but from an iPhone calendar, i believe.
#interface MasterViewController ()
#property (strong, nonatomic) NSMutableDictionary *sections;
#property (strong, nonatomic) NSArray *sortedDays;
#property (strong, nonatomic) NSDateFormatter *sectionDateFormatter;
#property (strong, nonatomic) NSDateFormatter *cellDateFormatter;
- (NSDate *)dateAtBeginningOfDayForDate:(NSDate *)inputDate;
- (NSDate *)dateByAddingYears:(NSInteger)numberOfYears toDate:(NSDate *)inputDate;
#end
#implementation MasterViewController
#synthesize sections;
#synthesize sortedDays;
#synthesize sectionDateFormatter;
#synthesize cellDateFormatter;
- (void)awakeFromNib
{
[super awakeFromNib];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
NSDate *now = [NSDate date];
NSDate *startDate = [self dateAtBeginningOfDayForDate:now];
NSDate *endDate = [self dateByAddingYears:1 toDate:startDate];
EKEventStore *eventStore = [[EKEventStore alloc] init];
NSPredicate *searchPredicate = [eventStore predicateForEventsWithStartDate:startDate endDate:endDate calendars:nil];
NSArray *events = [eventStore eventsMatchingPredicate:searchPredicate];
self.sections = [NSMutableDictionary dictionary];
for (EKEvent *event in events)
{
// Reduce event start date to date components (year, month, day)
NSDate *dateRepresentingThisDay = [self dateAtBeginningOfDayForDate:event.startDate];
// If we don't yet have an array to hold the events for this day, create one
NSMutableArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
if (eventsOnThisDay == nil) {
eventsOnThisDay = [NSMutableArray array];
// Use the reduced date as dictionary key to later retrieve the event list this day
[self.sections setObject:eventsOnThisDay forKey:dateRepresentingThisDay];
}
// Add the event to the list for this day
[eventsOnThisDay addObject:event];
}
// Create a sorted list of days
NSArray *unsortedDays = [self.sections allKeys];
self.sortedDays = [unsortedDays sortedArrayUsingSelector:#selector(compare:)];
self.sectionDateFormatter = [[NSDateFormatter alloc] init];
[self.sectionDateFormatter setDateStyle:NSDateFormatterLongStyle];
[self.sectionDateFormatter setTimeStyle:NSDateFormatterNoStyle];
self.cellDateFormatter = [[NSDateFormatter alloc] init];
[self.cellDateFormatter setDateStyle:NSDateFormatterNoStyle];
[self.cellDateFormatter setTimeStyle:NSDateFormatterShortStyle];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark - Date Calculations
- (NSDate *)dateAtBeginningOfDayForDate:(NSDate *)inputDate
{
// Use the user's current calendar and time zone
NSCalendar *calendar = [NSCalendar currentCalendar];
NSTimeZone *timeZone = [NSTimeZone systemTimeZone];
[calendar setTimeZone:timeZone];
// Selectively convert the date components (year, month, day) of the input date
NSDateComponents *dateComps = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:inputDate];
// Set the time components manually
[dateComps setHour:0];
[dateComps setMinute:0];
[dateComps setSecond:0];
// Convert back
NSDate *beginningOfDay = [calendar dateFromComponents:dateComps];
return beginningOfDay;
}
- (NSDate *)dateByAddingYears:(NSInteger)numberOfYears toDate:(NSDate *)inputDate
{
// Use the user's current calendar
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setYear:numberOfYears];
NSDate *newDate = [calendar dateByAddingComponents:dateComps toDate:inputDate options:0];
return newDate;
}
#pragma mark - UITableViewDataSource methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.sections count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSDate *dateRepresentingThisDay = [self.sortedDays objectAtIndex:section];
NSArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
return [eventsOnThisDay count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSDate *dateRepresentingThisDay = [self.sortedDays objectAtIndex:section];
return [self.sectionDateFormatter stringFromDate:dateRepresentingThisDay];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *reuseIdentifier = #"EventTitleCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
NSDate *dateRepresentingThisDay = [self.sortedDays objectAtIndex:indexPath.section];
NSArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
EKEvent *event = [eventsOnThisDay objectAtIndex:indexPath.row];
cell.textLabel.text = event.title;
if (event.allDay) {
cell.detailTextLabel.text = #"all day";
} else {
cell.detailTextLabel.text = [self.cellDateFormatter stringFromDate:event.startDate];
}
return cell;
}
#end
Is there a way for me to use my json event.startdate as a section header?
Personally, I would ignore the code you posted second there because its not what you are trying to do.
The part of the code where you set you header and subtitle are these two lines:
cell.textLabel.text = [NSString stringWithFormat:#"%#",event.title];
cell.detailTextLabel.text = [formatter stringFromDate: gmtDate];
So if you want the heading to be the date, just place it as the cell.textLabel.text value.
So if you are wanting to do sections.
Make sure the number of sections is greater then 1.
Then you might want to take a look at these table methods. Just depending on what your exact case and customization needs are you can change it accordingly.
(NSString*) tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section{
}
(CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section{
}
(UIView*)tableView:(UITableView*)table viewForHeaderInSection:(NsInteger)section{
}
I hope this helps. I normally would have an example I just didn't have the most available time currently, but if need be I can provide one.
Take Care :)

Getting a SIGABRT From Deleting a Row in a Table View

I am trying to have a table view list a number of objects that are stored in an array and it's working fine other than when I try to delete a row, it throws a SIGABRT. I checked at it is correctly updating the array. It seems that the SIGABRT has something to do with the number of sections in the table. Here is the code for the table view controller:
CalendarViewController.h
#import <UIKit/UIKit.h>
#import "Job.h"
#import "Shift.h"
#import "AppDelegate.h"
#interface CalendarViewController : UITableViewController
#property (nonatomic, strong) NSMutableArray *currentShiftsList;
#property (nonatomic, strong) AppDelegate *dataCenter;
#end
CalendarViewController.m
#import "CalendarViewController.h"
#interface CalendarViewController ()
#property (nonatomic, strong) NSMutableDictionary *sections;
#property (nonatomic, strong) NSArray *sortedShifts;
#property (strong, nonatomic) NSDateFormatter *sectionDateFormatter;
#property (strong, nonatomic) NSDateFormatter *cellDateFormatter;
#end
#implementation CalendarViewController
#synthesize sections, sortedShifts, currentShiftsList, dataCenter, sectionDateFormatter, cellDateFormatter;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (NSDate *)dateAtBeginningOfDayForDate:(NSDate *)inputDate {
// Use the user's current calendar and time zone
NSCalendar *calendar = [NSCalendar currentCalendar];
NSTimeZone *timeZone = [NSTimeZone systemTimeZone];
[calendar setTimeZone:timeZone];
// Selectively convert the date components (year, month, day) of the input date
NSDateComponents *dateComps = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:inputDate];
// Set the time components manually
[dateComps setHour:0];
[dateComps setMinute:0];
[dateComps setSecond:0];
// Convert back
NSDate *beginningOfDay = [calendar dateFromComponents:dateComps];
return beginningOfDay;
}
- (NSDate *)dateByAddingYears:(NSInteger)numberOfYears toDate:(NSDate *)inputDate
{
// Use the user's current calendar
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setYear:numberOfYears];
NSDate *newDate = [calendar dateByAddingComponents:dateComps toDate:inputDate options:0];
return newDate;
}
- (void)viewDidLoad
{
[super viewDidLoad];
dataCenter = (AppDelegate *)[[UIApplication sharedApplication] delegate];
currentShiftsList = [[NSMutableArray alloc] initWithArray:dataCenter.shiftsList];
self.sectionDateFormatter = [[NSDateFormatter alloc] init];
[self.sectionDateFormatter setDateStyle:NSDateFormatterLongStyle];
[self.sectionDateFormatter setTimeStyle:NSDateFormatterNoStyle];
self.cellDateFormatter = [[NSDateFormatter alloc] init];
[self.cellDateFormatter setDateStyle:NSDateFormatterNoStyle];
[self.cellDateFormatter setTimeStyle:NSDateFormatterShortStyle];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
self.sections = [NSMutableDictionary dictionary];
for (Shift *shift in dataCenter.shiftsList) {
// Reduce event start date to date components (year, month, day)
NSDate *dateRepresentingThisDay = [self dateAtBeginningOfDayForDate:shift.startDate];
// If we don't yet have an array to hold the events for this day, create one
NSMutableArray *shiftsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
if (shiftsOnThisDay == nil) {
shiftsOnThisDay = [NSMutableArray array];
// Use the reduced date as dictionary key to later retrieve the event list this day
[self.sections setObject:shiftsOnThisDay forKey:dateRepresentingThisDay];
}
// Add the event to the list for this day
[shiftsOnThisDay addObject:shift];
}
// Create a sorted list of days
NSArray *unsortedShifts = [self.sections allKeys];
self.sortedShifts = [unsortedShifts sortedArrayUsingSelector:#selector(compare:)];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [self.sections count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSDate *dateRepresentingThisDay = [self.sortedShifts objectAtIndex:section];
NSArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
return [eventsOnThisDay count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *reuseIdentifier = #"shifts";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
NSDate *dateRepresentingThisDay = [self.sortedShifts objectAtIndex:indexPath.section];
NSArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
Shift *shift = [eventsOnThisDay objectAtIndex:indexPath.row];
cell.textLabel.text = shift.jobtitle;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"h:mm a"];
NSString *start = [formatter stringFromDate:shift.startDate];
NSString *end = [formatter stringFromDate:shift.endDate];
NSString *detail = [[NSString alloc] initWithFormat:#"%# to %#", start, end];
cell.detailTextLabel.text = detail;
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSDate *dateRepresentingThisDay = [self.sortedShifts objectAtIndex:section];
return [self.sectionDateFormatter stringFromDate:dateRepresentingThisDay];
}
/*
// 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 editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[currentShiftsList removeObjectAtIndex:indexPath.row];
dataCenter.shiftsList = currentShiftsList;
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// 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];
*/
}
#end
This doesn't make sense to me.
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
Why isn't it just:
[tableView deleteRowsAtIndexPaths:indexPath.row withRowAnimation:UITableViewRowAnimationFade];
Also remember a reload TableView after delete (if you want it).
When you delete a row, you are removing an item from the currentShiftsList array. However, you are not using that array in your UITableViewDataSource related methods. The TableView is expecting there to be 1 less item from its DataSource, but you will be returning the original number of items instead.
Overall, things are very confusing because you have several collections that are trying to manage the same set of data (or copies of that data). Try looking into CoreData and the NSFetchedResultsController which is specifically made to managed a set of data and propagate any changes to a UITableView.

Resources