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.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am trying to display content in my UITableView in my UIViewController.
My table view is in a regular view called todayView which is in a UIViewController called Calendar
I connected the datasource and delegate to Calendar and added all of the methods for table view, but it still doesn't work.
Currently, my code looks like this
Is there anything I am doing wrong?
#implementation SecondViewController {
NSMutableArray *tableData;
}
-(BOOL)prefersStatusBarHidden{
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSDate *today = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MMMM dd, yyyy"];
NSString *dateString = [dateFormatter stringFromDate:today];
self.dateLabel.text = dateString;
Event *e1 = [[Event alloc] init];
e1.name = #"All School Mass";
e1.time = #"All Day";
[tableData addObject:e1];
Event *e2 = [[Event alloc] init];
e2.name = #"Tennis - Moreau Catholic vs James Logan";
e2.time = #"4:00 pm at Moreau Catholic";
[tableData addObject:e2];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if(cell == nil)
{
//Create your cell
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//Configure your cell
Event *event = [tableData objectAtIndex:indexPath.row];
cell.textLabel.text = event.name;
return cell;
}
Have you initialized that tableData mutable Array ?
i think you hav'nt initialized it thats why its all happening.
Please allocate it
tableData= [NSMutableArray array];
than add some objects .
otherwise tableData.count will return always zero.
so no data will be display.
You may forget this method
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
you can implement it and return 1.
I am allowing users to choose a date from UIDatePicker view and then the title of the UITableView will show the dates from the picker view . My question is, is it possible for the UITableView to rearrange the items from old to new according to the date of the UITableView title automatically and reload the table?
Here are my code,
#interface PictureListMainTable : UITableViewController{
}
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (strong, nonatomic) NSMutableArray *pictureListData;
- (void)readDataForTable;
#end
#synthesize managedObjectContext, pictureListData;
#synthesize scroll;
- (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
Thanks.
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];
}
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 :)
The YApp crashes whenever I press the Delete button from the simulator in iPhone. I have copied some code from my project here. How can I solve the delete bug?
I found a similar question, Error in the delete function of the alarm app in iPhone, but it does not answer my question.
My code is below.
#import "FirstPage.h"
#implementation FirstPage
#synthesize datePicker, eventText,tableview;
- (void) viewWillAppear:(BOOL)animated {
[self.tableview reloadData];
}
- (IBAction) scheduleAlarm:(id) sender {
[eventText resignFirstResponder];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
// Get the current date
NSDate *pickerDate = [self.datePicker date];
// Break the date up into components
NSDateComponents *dateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:pickerDate];
NSDateComponents *timeComponents = [calendar components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:pickerDate];
// Set up the fire time
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
// Notification will fire in one minute
[dateComps setMinute:[timeComponents minute]];
[dateComps setSecond:[timeComponents second]];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
[dateComps release];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = itemDate;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
// Notification details
localNotif.alertBody = [eventText text];
// Set the action button
localNotif.alertAction = #"View";
localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.applicationIconBadgeNumber = 1;
// Specify custom data for the notification
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:#"someValue" forKey:#"someKey"];
localNotif.userInfo = infoDict;
// Schedule the notification
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
[localNotif release];
[self.tableview reloadData];
}
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
}
return self;
}
*/
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
[eventText resignFirstResponder];
return YES;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
Array = [[NSMutableArray alloc]init];
eventText.delegate = self;
[super viewDidLoad];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
int count = [Array count];
if(self.editing) count++;
//return count;
return [[[UIApplication sharedApplication] scheduledLocalNotifications] 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:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
NSArray *notificationArray = [[UIApplication sharedApplication] scheduledLocalNotifications];
// notificationArray = Array;
notif = [notificationArray objectAtIndex:indexPath.row];
[cell.textLabel setText:notif.alertBody];
[cell.detailTextLabel setText:[notif.fireDate description]];
return cell;
}
- (IBAction)DeleteButtonAction:(id)sender
{
[Array removeLastObject];
[tableview reloadData];
}
- (IBAction) EditTable:(id)sender
{
if(self.editing)
{
[super setEditing:NO animated:NO];
[tableview setEditing:NO animated:NO];
// [tableview reloadData];
// [self.navigationItem.leftBarButtonItem setTitle:#"Edit"];
// [self.navigationItem.leftBarButtonItem setStyle:UIBarButtonItemStylePlain];
}
else
{
[super setEditing:YES animated:YES];
[tableview setEditing:YES animated:YES];
// [tableview reloadData];
// [self.navigationItem.leftBarButtonItem setTitle:#"Done"];
// [self.navigationItem.leftBarButtonItem setStyle:UIBarButtonItemStyleDone];
}
}
// The editing style for a row is the kind of button displayed to the left of the cell when in editing mode.
- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
// No editing style if not editing or the index path is nil.
if (self.editing == NO || !indexPath) return UITableViewCellEditingStyleNone;
// Determine the editing style based on whether the cell is a placeholder for adding content or already
// existing content. Existing content can be deleted.
if (self.editing && indexPath.row == ([Array count]))
{
return UITableViewCellEditingStyleInsert;
} else
{
return UITableViewCellEditingStyleDelete;
}
return UITableViewCellEditingStyleNone;
}
// Update the data model according to edit actions delete or insert.
- (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[Array removeObjectAtIndex:indexPath.row];
// [tableview reloadData];
} else if (editingStyle == UITableViewCellEditingStyleInsert)
{
}
}
#pragma mark Row reordering
// Determine whether a given row is eligible for reordering or not.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
// Process the row move. This means updating the data model to correct the item indices.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath
toIndexPath:(NSIndexPath *)toIndexPath
{
NSString *item = [[Array objectAtIndex:fromIndexPath.row] retain];
[Array removeObject:item];
[Array insertObject:item atIndex:toIndexPath.row];
[item release];
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload {
datePicker = nil;
tableview = nil;
eventText = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
I think the problem is in the section listed below.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
int count = [Array count];
if(self.editing) count++;
//return count;
return [[[UIApplication sharedApplication] scheduledLocalNotifications] count];
}