Auto rearrangement of uitableviewcell item - ios

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.

Related

how to get the selected cell values and unselected cell values in uitableview in different array using objective c

pls check the image
i am very new to iOS how to get the selected cell values in one array and unselected cell value in the another array using by using checkmarks in objective c
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *selectedRows=[_mytableview indexPathsForSelectedRows];
indexofselectedcell = [[NSMutableArray alloc]init];
valueofselectedcell = [[NSMutableArray alloc]init];
for (int i=0; i<selectedRows.count; i++) {
[indexofselectedcell addObject:indexPath
customcell *cell = (customcell *)[_mytableview cellForRowAtIndexPath:indexPath];
NSString *test = cell.balance.text;
[valueofselectedcell addObject:test];
NSLog(#"%# the value of the selected cell value is ",valueofselectedcell);
NSArray *array = [valueofselectedcell copy];
NSNumber* sum = [array valueForKeyPath: #"#sum.self"];
NSLog(#"the sum valuie is .... %#",sum);
NSString *totalamount = [sum stringValue];
_amountlabel.text=totalamount;
NSInteger index = [valueofselectedcell indexOfObject:totalamount];
NSLog(#"%ld the index value in the array is",(long)index);
}}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *totalamount;
if ([indexofselectedcell containsObject: indexPath])
{
NSInteger anIndex=[indexofselectedcell indexOfObject:indexPath];
[indexofselectedcell removeObjectAtIndex:anIndex];
[valueofselectedcell removeObjectAtIndex:anIndex];
NSLog(#"the value of the unselected cell value is..... %#",valueofselectedcell);
NSArray *array = [valueofselectedcell copy];
NSNumber* sum = [array valueForKeyPath: #"#sum.self"];
totalamount = [sum stringValue];
_amountlabel.text=totalamount;
totalamount= nil;
} }
Pavithra I tried sample project for your question and output.If I get unselected and selected cells in separate array,it crashed as I could not check two array in cellForRowAtIndexPath.So that I save selected and unSelected values in one array.
I created simple understandable solution.I have set values in tableview as unselected as default.If you selected(when you click the cell) it shows UITableViewCellAccessoryCheckmark and other show UITableViewCellAccessoryNone.
It works perfectly.You can easily get.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (strong, nonatomic) IBOutlet UITableView *tableViewSelectUnSelect;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController (){
NSMutableArray *arrVal,*arrSelectedUnSelectedValues,*arrSelectedValues,*arrUnSelectedValues;
NSMutableArray *arrSubTitle;
}
#end
#implementation ViewController
#synthesize tableViewSelectUnSelect;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrVal= [[NSMutableArray alloc]initWithObjects:#"India",#"China",#"Korea",#"Japan",#"Peru",#"Italy",#"France",#"US",#"Dubai",#"UK",#"Nepal",nil];
arrSubTitle = [[NSMutableArray alloc]initWithObjects:#"100",#"70",#"80",#"90",#"50",#"60",#"70",#"50",#"40",#"30",#"80",nil];
arrSelectedUnSelectedValues= [[NSMutableArray alloc]init];
arrSelectedValues = [[NSMutableArray alloc]init];
arrUnSelectedValues = [[NSMutableArray alloc]init];
for(int j=0;j<[arrVal count];j++)
{
[arrSelectedUnSelectedValues addObject:#"unselected"]; //As Default it is in UnSelected State
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UITableViewDataSource Methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arrVal.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *strCell = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strCell];
if(cell==nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:strCell];
}
if([[arrSelectedUnSelectedValues objectAtIndex:indexPath.row] isEqualToString:#"selected"])
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
cell.textLabel.text = [arrVal objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [arrSubTitle objectAtIndex:indexPath.row];
return cell;
}
#pragma mark - UITableViewDelegate Methods
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
#try
{
CGPoint touchPoint = [cell convertPoint:CGPointZero toView:tableViewSelectUnSelect];
NSIndexPath *indexPath = [tableViewSelectUnSelect indexPathForRowAtPoint:touchPoint];
NSLog(#"The arrSelectedUnSelectedValues are %#",arrSelectedUnSelectedValues );
NSString *strValue;
if([arrSelectedUnSelectedValues count]==0)
{
for(int i=0; i<[arrVal count]; i++)
{
[arrSelectedUnSelectedValues addObject:#"unselected"];
}
}
if([[arrSelectedUnSelectedValues objectAtIndex:indexPath.row] isEqualToString:#"selected"])
{
cell.accessoryType = UITableViewCellAccessoryNone;
[arrSelectedUnSelectedValues replaceObjectAtIndex:indexPath.row withObject:#"unselected"];
strValue = cell.detailTextLabel.text;
[arrUnSelectedValues addObject:strValue];
NSLog(#"The arrUnSelectedValues are - %#",arrUnSelectedValues);
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[arrSelectedUnSelectedValues replaceObjectAtIndex:indexPath.row withObject:#"selected"];
strValue = cell.detailTextLabel.text;
[arrSelectedValues addObject:strValue];
NSLog(#"The arrSelectedValues - %#",arrSelectedValues);
}
}
#catch (NSException *exception) {
NSLog(#"The exception is-%#",exception);
}
}
#end
First when I run the application it shows like below
Then when I select values from the tableView
Then finally printed results are

pass value in splitview detailview

I have a splitview app, a table with customers to the left and their info on the right so i have to pass witch customer that is clicked and i can't use the name in case of two have the same so im trying to pass over the customer id in the tag property of the cell but i dont get it to work.
Here is where i set the value, i can see it's working when debugging
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
Customer names
NSDate *object = _objects[indexPath.row];
//Customer number
NSString *nr = _kundnr[indexPath.row];
//Customer name
cell.textLabel.text = [object description];
//Customer number
NSInteger Ftgnr = [nr intValue];
//Setting the customer number to cell tag
cell.tag = Ftgnr;
return cell;
}
Here i pick up the cell.tag it's the detailview viewdidload, i tried many different ways to save the id to a variable but the app crashes and i don't know if the value gets passed.
It's working to pick up the description (customer name) but i want the id.
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
// NSString *strCellTag = [NSString stringWithFormat:#"%d", [self.detailItem tag]];
//here im trying to pick up the tag value this is where the app craches
NSInteger Ftgnr = [self.detailItem tag];
// NSString *stringformat = [NSString stringWithFormat:#"%d", Ftgnr];
//Its working to pick up the text from the cell
self.detailDescriptionLabel.text = [self.detailItem description];
}
Thank you for your help!
Add a property to your detail view controller so you can set the id when you set the detail item. Then:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.detailViewController.detailIdentity = _kundnr[indexPath.row];
self.detailViewController.detailItem = _objects[indexPath.row];
}
And then use self.detailIdentity instead of [self.detailItem tag]. And, it's already a string so you don't need to convert to integer and back.
You should probably also:
Rename detailItem to be more specific, like detailDate
Think about creating a custom class to hold the full detailItem (so it contains the identity and the date)
My final code
Masterviewcontroller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSDate *object = _objects[indexPath.row];
cell.textLabel.text = [object description];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDate *object = _objects[indexPath.row];
NSDate *kundnr = _kundnr[indexPath.row];
self.detailViewController.detailItem = object;
self.detailViewController.detailIdentity = kundnr;
}
Detailviewcontroller
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)setDetailIdentity:(id)newDetailItentity
{
if (_detailIdentity != newDetailItentity) {
_detailIdentity = newDetailItentity;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
// NSString *stringformat = [NSString stringWithFormat:#"%d", Ftgnr];
self.detailDescriptionLabel.text = [self.detailItem description];
}
if (self.detailIdentity) {
NSString *kundnr = [self.detailIdentity description];
}
}

To Segue or to didSelectRowAtIndexPath?

Below is the code that I am currently running. I have a storyboard setup with a nav controller and tableview controller and a view controller. I am trying to pass the name from the NSDictionary that I have setup for the Table to the detail view controller. Should I use prepareforsegue or didselectrowatindexpath and how would I get the name out of the dictionary to pass it along?
#import "FMInboxViewController.h"
#import "FMDetailViewController.h"
#interface FMInboxViewController ()
#end
#implementation FMInboxViewController
#synthesize keyArray;
#synthesize tableArray;
#synthesize tblDictionary;
#synthesize filteredArray;
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *ary=[[NSMutableArray alloc]init];
[ary addObject:#"Adam"];
[ary addObject:#"Fred"];
[ary addObject:#"Angel"];
// ... many similar entries
[ary addObject:#"James"];
[ary addObject:#"Mukthesh"];
self.tblDictionary =[self fillingDictionary:ary];
}
Table View Data Source
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [keyArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSArray *ary = [self.tblDictionary valueForKey:[keyArray objectAtIndex:section]];
return [ary count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSString *key = [keyArray objectAtIndex:[indexPath section]];
NSArray *array = (NSArray *)[self.tblDictionary valueForKey:key];
NSString *cellTitle = [array objectAtIndex:[indexPath row]];
cell.textLabel.text = cellTitle;
// Configure the cell...
return cell;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *title = [keyArray objectAtIndex:section];
return title;
}
//-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// NSString *key = [keyArray objectAtIndex:[indexPath section]];
// NSArray *array = (NSArray *)[self.tblDictionary valueForKey:key];
// self.selectedName = [array objectAtIndex:indexPath.row];
// NSLog(#"Selected Name in Did select: %#", self.selectedName);
//
// [self performSegueWithIdentifier:#"showDetail" sender:self];
//}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showDetail"]) {
NSIndexPath *section = [self.tableView indexPathForSelectedRow];
NSString *key = [keyArray objectAtIndex:section];
NSArray *array = (NSArray *)[self.tblDictionary valueForKey:key];
NSString *cellTitle = [array objectAtIndex:[indexPath row]];
NSLog(#"Selected Name in Did select: %#", self.selectedName);
}
}
Helper methods
#pragma mark - Helper Methods
- (NSMutableDictionary *)fillingDictionary:(NSMutableArray *)sentArray {
keyArray = [[NSMutableArray alloc] init];
[keyArray removeAllObjects];
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
[sentArray sortUsingSelector:#selector(compare:)];
for ( NSString *str in sentArray) {
NSString *charVal = [str substringToIndex:1];
NSString *charStr = [NSString stringWithString:charVal];
NSLog(#" charStr = %#", charStr);
if (![keyArray containsObject:charStr]) {
NSMutableArray *charArray = [[NSMutableArray alloc] init];
[charArray addObject:str];
[keyArray addObject:charStr];
[dic setValue:charArray forKey:charStr];
}
else {
NSMutableArray *prevArray = (NSMutableArray *)[dic valueForKey:charStr];
[prevArray addObject:str];
[dic setValue:prevArray forKeyPath:charStr];
}
}
return dic;
}
#end
OK, I changed that section to look like this
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *key = [keyArray objectAtIndex:[indexPath section]];
NSArray *array = (NSArray *)[self.tblDictionary valueForKey:key];
self.selectedName = [array objectAtIndex:indexPath.row];
NSLog(#"Selected Name in Did select: %#", self.selectedName);
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
FMDetailViewController *dvc = (FMDetailViewController *)segue.destinationViewController;
dvc.name = self.selectedName;
}
However now when I select row the name won't show up in the detail controller on the first press. If you go back and select another name the first name that you pressed then shows up in the view controller. Any suggestions on why this occurs?
You need to use both, in didSelectRowAtIndexPath you should call [self performSegueWithIdentifier:#"identifier" sender:self];
In the same View Controller you should have the prepareForSegue method grab the destinationViewController out of the segue, and then set whatever properties on that view controller that you wish to set.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.someProperty = [self.someArray objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"segueID" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *vcToPushTo = segue.destinationViewController;
vcToPushTo.propertyToSet = self.someProperty;
}
If possible (and this is the case in almost all standard scenarios), I would use Interface Builder to trigger the segue. You still need to implement prepareForSegue: to configure the destination view controller.
In order to create a segue in IB which triggers a detail view when tapping on a cell or an accessory button (on the right most side of the cell) perform these steps:
Control drag from Table View Cell to the destination view controller and release the mouse or trackpad. This opens small selection panel.
Choose the source of the trigger, either "Selection segue" or "Accessory action" and the type of the segue ("push", "modal" or "custom").
In the Attributes Inspector pane define the "Identifier" of the segue, e.g. "UserShowSegue".
Here's an image from a Demo storyboard in IB which illustrates how the "Table View Cell" in the "Users" view controller is setup to trigger a "push" segue to a detail view controller:
Might be an old question, but to be more detailed for whom it may concern:
1- Use both as '(#Peter-Foti)' mentioned.
2- Segue should be linked from the ParentVC to the DestinationVC (NOT from the Prototype Cell).
3- Sender should be set properly.
4- set your '#property (someProperty)'.
SAMPLE CODE:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.someProperty = [self.someArray objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"segueID" sender:self.someProperty];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *vcToPushTo = segue.destinationViewController;
vcToPushTo.propertyToSet = sender;
}
Because didSelectRowAtIndexPath can be replaced with storyboard visual programming, I recommend to do all the logic in the prepareForSegue like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let cell = sender as! UITableViewCell
let indexPath = tableView.indexPath(for: cell)!
... and then use indexPath to set up the destination
}

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];
}

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