I am adding values into 2 entities within my core data model and the problem I am facing is trying to properly retrieve the NSSet and target the associated strings when accessing the detail view.I would simply like to display the results in a uitableview. I believe the values are being correctly added along with the relationships to the entities as I previously got help off the forum for it as viewable here. I am trying to recall the associated RoutinesDetail data on the detail view.
I know the seague is working correctly as I am able to set the title based on the selectedRow, so it is passing the data between view controllers. I can recall 'Routines' data using Ex.routinename
Using the following to debug and try to allocate the NSSet as I read a way to display it was to use allObjects but this didn't work:
NSArray *test= [Ex.routinedet allObjects];
NSSortDescriptor *desc = [[NSSortDescriptor alloc] initWithKey:#"image"
ascending:YES];
test = [test sortedArrayUsingDescriptors:[NSArray arrayWithObject:desc]];
NSLog(#"Image *** %#",test);
This produces the following report which makes me question whether I am doing it right?
"<RoutinesDetails: 0x7453d80> (entity: RoutinesDetails; id: 0x74531f0
<x-coredata://C075DDEC-169D-46EC-A4B7-972A04FCED70/RoutinesDetails/p1>
; data: <fault>)"
)
So basically I am looking at how to retrieve RoutinesDetails. Any suggestions would be greatly appreciated.
**
In case it is needed here is the associated code
**
routines.h - NSManagedObject
#class RoutinesDetails;
#interface Routines : NSManagedObject
#property (nonatomic, retain) id routinename;
#property (nonatomic, retain) NSSet *routinedet;
#end
#interface Routines (CoreDataGeneratedAccessors)
- (void)addRoutinedetObject:(RoutinesDetails *)value;
- (void)removeRoutinedetObject:(RoutinesDetails *)value;
- (void)addRoutinedet:(NSSet *)values;
- (void)removeRoutinedet:(NSSet *)values;
#end
RoutinesDetails.h - NSManagedObject
#class Routines;
#interface RoutinesDetails : NSManagedObject
#property (nonatomic, retain) NSString * image;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) Routines *routineinfo;
#end
FBCDRoutineDetailViewController(sorry if its too much code)
#import "FBCDRoutineDetailViewController.h"
#import "FBCDRoutineViewController.h"
#import "Routines.h"
#import "RoutinesDetails.h"
#interface FBCDRoutineDetailViewController ()
#end
#implementation FBCDRoutineDetailViewController
#synthesize managedObjectContext;
#synthesize fetchedResultsController = _fetchedResultsController;
#synthesize Ex;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"RoutinesDetails" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]
initWithKey:#"name" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext sectionNameKeyPath:nil
cacheName: nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
- (void)viewDidLoad
{
[[self navigationController] setNavigationBarHidden:NO animated:YES];
[super viewDidLoad];
// Do any additional setup after loading the view.
NSArray *test= [Ex.routinedet allObjects];
NSSortDescriptor *desc = [[NSSortDescriptor alloc] initWithKey:#"image"
ascending:YES];
test = [test sortedArrayUsingDescriptors:[NSArray arrayWithObject:desc]];
NSLog(#"Image *** %#",test);
self.title = Ex.routinename;
NSLog(#"Image *** %#",Ex.routinename);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view delegate
- (IBAction)save:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)cancel:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{ }
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { }
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id sectionInfo =
[[_fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
//RoutinesDetails *info = [_fetchedResultsController objectAtIndexPath:indexPath];
NSArray *test= [Ex.routinedet allObjects];
NSSortDescriptor *desc = [[NSSortDescriptor alloc] initWithKey:#"image"
ascending:YES];
test = [test sortedArrayUsingDescriptors:[NSArray arrayWithObject:desc]];
//cell.textLabel.text = info.image;
cell.textLabel.text = [[test objectAtIndex:indexPath.row] name];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"routineCell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Set up the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
Any suggestions would be greatly appreciated.
I think you are seeing what you want. I assume EX is an exercise, a routine, and that you are trying to print out the associated details. Your debugging statement displays one RoutinesDetails
(entity: RoutinesDetails; id: 0x74531f0 ; data: )" )
Try this to help you visualize
for (RoutinesDetails *detail in Ex.routinedet) {
NSLog(#"image: %#, name: %#, routineName: %#",detail.image, detail.name, detail.routineinfo.routinename);
}
Related
My app follows the scheme web(json)->appDelegate (Core Data)->ViewController. So far I can see the locations I got from serialized json and all the other new ones I input for testing. But now I'm trying to display them in a tableview, and so far it's not working. The table remains empty, although I know the locations are in the Core Data: Here's the code:
#import "TableTableViewController.h"
#import "DetailViewController.h"
#import <CoreData/CoreData.h>
#import "Spot.h"
#import "AppDelegate.h"
#interface TableViewController ()
#property (strong) NSMutableArray *locations;
#end
#implementation TableViewController
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate respondsToSelector:#selector(managedObjectContext)]){
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Spot"];
self.locations = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.locations.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSManagedObject *ls = [self.locations objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%#", [ls valueForKey:#"name"]]];
return cell;
}
Can someone tell me what am I doing wrong?
UPDATE:
If I log the locations-> NSLog(#"%# the locations are", _locations); I get a null result. This means that the fetched data isn't populating the array, therefore, the table stays empty, right? But why the array isn't being populated?
Check that your self.tableView.dataSource is not nil
I would like to explain the most detailed the problem I'm facing.
Previously instead of the UIViewController i had directly a UITableViewController, the problem is that now i need to show more content in the view that just the tableview so i created a new view. Now i have a UIViewController that has: UIScrollView. Enside of it there are: 1. UIView + 1 UITableView
I'm using AutoLayout. And is working fine. The problem I'm facing is that since i switched to use this view I'm unable to display content in the table with coredata. I was able to do it without coredata but not with it.
In the interfacebuilder i set datasource and delegate to this UIViewController.
Header:
#import <UIKit/UIKit.h>
#interface ResultsExtraVC : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property(nonatomic, strong) AGTCoreDataStack *model;
#property (strong, nonatomic) IBOutlet UILabel *labelRaceTime;
#property (strong, nonatomic) IBOutlet UILabel *labelTrackCondition;
#property (strong, nonatomic) IBOutlet UILabel *labelRaceStarttime;
#property (strong, nonatomic) IBOutlet UILabel *labelRaceMode;
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) IBOutlet UIView *raceInfoView;
#property(nonatomic, strong)NSNumber *eventID;
#property(nonatomic, strong)NSNumber *sectionID;
#property(nonatomic, strong)NSNumber *elementID;
#property(nonatomic, strong)NSNumber *categoryID;
#end
Implementation:
#import "ResultsExtraVC.h"
#import "ResultsExtraCellVC.h"
#import "Result.h"
#import "Element.h"
#import "Section.h"
#import <CoreData/CoreData.h>
#interface ResultsExtraVC () <NSFetchedResultsControllerDelegate>
//Core data
#property (nonatomic,strong) NSManagedObjectContext* managedObjectContext;
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#end
static NSString * const cellIdentifier = #"resultsExrtaAltCell";
#implementation ResultsExtraVC
#synthesize managedObjectContext;
#synthesize fetchedResultsController = _fetchedResultsController;
#synthesize eventID, sectionID, elementID, categoryID, model;
- (void)viewDidLoad {
[super viewDidLoad];
managedObjectContext = self.model.context;
[self getResults];
NSLog(#"ElementName: %#", [self getElementName]);
NSLog(#"SectionName: %#", [self getSectionName]);
[self configureHeatInfo];
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.fetchedResultsController = nil;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - View Configuration
-(void) configureHeatInfo{
_scrollView.backgroundColor = [UIColor cyanColor];
_scrollView.translatesAutoresizingMaskIntoConstraints = NO;
_labelRaceTime.translatesAutoresizingMaskIntoConstraints = NO;
_labelRaceTime.text = #"Race time:\n10:00";
_labelRaceMode.translatesAutoresizingMaskIntoConstraints = NO;
_labelRaceMode.text = #"Mode: Groupstart";
_labelTrackCondition.translatesAutoresizingMaskIntoConstraints = NO;
_labelTrackCondition.text = #"Track Condition: Dry";
_labelRaceStarttime.translatesAutoresizingMaskIntoConstraints = NO;
_labelRaceStarttime.text = #"Starttime: 12.03.2016 11:09:10";
//self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
/*self.tableView.dataSource = self;
self.tableView.delegate = self;*/
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[self.fetchedResultsController sections] count];
}
/*- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}*/
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];
#ifndef NDEBUG
NSLog(#"%s (line:%d) - Rows: %lu",__PRETTY_FUNCTION__,__LINE__, (unsigned long)[sectionInfo numberOfObjects]);
#endif
// Return the number of rows in the section.
return [sectionInfo numberOfObjects];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
return [self basicCellAtIndexPath:indexPath];
}
- (ResultsExtraCellVC *)basicCellAtIndexPath:(NSIndexPath *)indexPath {
ResultsExtraCellVC *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// Using a cell identifier will allow your app to reuse cells as they come and go from the screen.
if (cell == nil) {
#ifndef NDEBUG
NSLog(#"%s (line:%d)",__PRETTY_FUNCTION__,__LINE__);
#endif
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ResultsExtraCell" owner:self options:nil];
cell = (ResultsExtraCellVC *)[nib objectAtIndex:0];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(ResultsExtraCellVC *)cell atIndexPath:(NSIndexPath *)indexPath {
#ifndef NDEBUG
NSLog(#"%s (line:%d)",__PRETTY_FUNCTION__,__LINE__);
#endif
Result *result = [_fetchedResultsController objectAtIndexPath:indexPath];
[cell.cellRankNr setText:[NSString stringWithFormat:#"%#",[result endposition]]];
[cell.cellName setText:[NSString stringWithFormat:#"%# %# (%#)",[result pilotprename], [result pilotname], [result carnumber]]];
[cell.cellResult setText:[NSString stringWithFormat:#"%#",NSLocalizedFormatString(#"LapsXnTimeX",[result rlaps],[result rendtime])]];
[cell.cellRace setText:[NSString stringWithFormat:#"%#",NSLocalizedFormatString(#"BestTimeXnAvgTimeX",[result rbesttime], [result rmediumtime])]];
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView respondsToSelector:#selector(setSeparatorInset:)])
{
[tableView setSeparatorInset:UIEdgeInsetsZero];
}
if ([tableView respondsToSelector:#selector(setLayoutMargins:)])
{
[tableView setLayoutMargins:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:#selector(setLayoutMargins:)])
{
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
-(NSString *)getElementName{
NSString *elementName = #"";
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Elements" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init] ;
[request setEntity:entityDescription];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(eventid = %# AND sectionid = %# AND elementid = %# AND categoryid= %#)",eventID, sectionID, elementID, categoryID];
[request setPredicate:predicate]; //added this line later
NSArray *array = [managedObjectContext executeFetchRequest:request error:nil];
if([array count]> 0){
Element *element = [array lastObject];
elementName = [element name];
}
return elementName;
}
-(NSString *)getSectionName{
NSString *sectiontName = #"";
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Sections" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init] ;
[request setEntity:entityDescription];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(eventid = %# AND sectionid = %#)",eventID, sectionID];
[request setPredicate:predicate]; //added this line later
NSArray *array = [managedObjectContext executeFetchRequest:request error:nil];
if([array count]> 0){
Section *section = [array lastObject];
sectiontName = [section name];
}
return sectiontName;
}
-(void)getResults{
// Initialize Fetch Request
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Results"];
// Add Sort Descriptors
//[fetchRequest setSortDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"endposition" ascending:YES]]];
//Predicate
NSPredicate *commentsPredicate = [NSPredicate predicateWithFormat:#"(eventid = %# AND sectionid = %# AND elementid = %#)",eventID, sectionID, elementID];
[fetchRequest setPredicate:commentsPredicate]; //added this line later
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"endposition"
ascending:YES];
NSArray *sortDescriptors = #[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
// Initialize Fetched Results Controller
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
// Configure Fetched Results Controller
[self.fetchedResultsController setDelegate:self];
// Perform Fetch
NSError *error = nil;
[self.fetchedResultsController performFetch:&error];
if (error) {
NSLog(#"Unable to perform fetch.");
NSLog(#"%#, %#", error, error.localizedDescription);
}
}
#pragma mark -
#pragma mark Fetched Results Controller Delegate Methods
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
switch (type) {
case NSFetchedResultsChangeInsert: {
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
case NSFetchedResultsChangeDelete: {
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
case NSFetchedResultsChangeUpdate: {
[self configureCell:(ResultsExtraCellVC *)[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
}
case NSFetchedResultsChangeMove: {
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
}
#end
My View looks like this:
I tried to follow some tutorials as this is the first time i'm doing this with CoreData, previously i always used only UITableViewController.
I followed this: http://code.tutsplus.com/tutorials/core-data-from-scratch-more-nsfetchedresultscontroller--cms-21777
And also checked: CoreData TableView inside UIViewController
But with no success.
I would be great if someone can help me with the problem.
Thanks in advance
Maybe in code line
// Initialize Fetched Results Controller
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
the sectionNameKeyPath is missing? It must be one of the NSSortDescriptor keys.
I'm working on an iOS app written in Objective-C and I have table view with many records from Core data. When I delete one record the row is deleted from Core data but the app is giving me an error:
-[_PFArray removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fbf5be5e6b0
I have tried many times to change this but it still crashes the app or the table view is not updated after deletion.
This is my header file:
#import <UIKit/UIKit.h>
#include "Notes.h"
#interface ShowClassNote : UIViewController<UITabBarDelegate,UITableViewDataSource>
// get moodle id from segue
#property(strong,nonatomic)NSString*moodeleID;
#property(strong,nonatomic)NSString*moodleName;
#property(strong,nonatomic)NSString*content;
#property (nonatomic, strong) NSMutableArray *fetchedObjects;
#property(strong)NSManagedObjectContext*passThis;
#property(strong,nonatomic)NSString*dataForSend;
#property(strong,nonatomic)NSArray*noteID;
#property(strong,nonatomic)NSArray*noteTitle;
#property(strong,nonatomic)NSArray*insertDates;
#property(strong,nonatomic)NSArray*noteContent;
#property (weak, nonatomic) IBOutlet UILabel *classTitleLable;
#property (weak, nonatomic) IBOutlet UITableView *allNotes;
#end
and this is my implementation file:
#import "ShowClassNote.h"
#import "Subjects.h"
#import "NewClassNote.h"
#import "Notes.h"
#import "AllClassNotesCell.h"
#interface ShowClassNote ()
#end
#implementation ShowClassNote
- (void)viewDidLoad {
[super viewDidLoad];
id delegate =[[UIApplication sharedApplication]delegate];
NSError*error=nil;
NSManagedObjectContext *context = [delegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Notes"
inManagedObjectContext:context];
NSPredicate * predicate =[NSPredicate predicateWithFormat:[NSString stringWithFormat:#"moodleCode=='%#'",self.moodeleID]];
[fetchRequest setPredicate:predicate];
[fetchRequest setEntity:entity];
self.fetchedObjects = [[NSMutableArray alloc]initWithObjects:[context executeFetchRequest:fetchRequest error:&error], nil];
// self.fetchedObjects =(NSMutableArray *) [context executeFetchRequest:fetchRequest error:&error];
// NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
self.noteTitle =[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"title"];
self.insertDates =[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"insertDate"];
self.noteContent =[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"content"];
self.noteID=[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"moodleCode"];
self.classTitleLable.text=self.moodleName;
self.title=self.moodleName;
[self.allNotes reloadData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
return 0;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
// This will create a "invisible" footer
return 0.01f;
}
#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.
return [self.fetchedObjects count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * cellIdnt =#"noteCell";
AllClassNotesCell *cell =(AllClassNotesCell *) [tableView dequeueReusableCellWithIdentifier:cellIdnt forIndexPath:indexPath];
// Configure the cell...
// Get current date & time
NSDate *currDate = [self.insertDates objectAtIndex:indexPath.row];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"dd/MM/YY HH:mm"];
NSString* dateToString =[dateFormatter stringFromDate:currDate];
cell.textLabel.text= [self.noteTitle objectAtIndex:indexPath.row] ;
cell.detailTextLabel.text=dateToString;
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 78;
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
id delegate =[[UIApplication sharedApplication]delegate];
// Delete the role object that was swiped
NSUInteger currentSelect = indexPath.row;
NSManagedObjectContext *context = [delegate managedObjectContext];
Notes * roleToDelete= [self.fetchedObjects objectAtIndex:currentSelect];
[context deleteObject:roleToDelete];
// Save the context.
NSError *error;
if (![context save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
[_fetchedObjects removeObjectAtIndex:currentSelect];
[self.allNotes reloadData];
}
-(void)viewWillAppear:(BOOL)animated{
id delegate =[[UIApplication sharedApplication]delegate];
NSError*error=nil;
NSManagedObjectContext *context = [delegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Notes"
inManagedObjectContext:context];
NSPredicate * predicate =[NSPredicate predicateWithFormat:[NSString stringWithFormat:#"moodleCode=='%#'",self.moodeleID]];
[fetchRequest setPredicate:predicate];
[fetchRequest setEntity:entity];
self.fetchedObjects = (NSMutableArray *)[context executeFetchRequest:fetchRequest error:&error];
self.noteTitle =[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"title"];
self.insertDates =[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"insertDate"];
self.classTitleLable.text=self.moodleName;
self.title=self.moodleName;
[self.allNotes reloadData];
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier]isEqual:#"newNote"]) {
NewClassNote * newNoteView =[segue destinationViewController];
newNoteView.moodleID =self.moodeleID;
newNoteView.newOrOld =YES;
}else if ([[segue identifier]isEqual:#"showNote"])
{
NewClassNote * dvc =[segue destinationViewController];
NSUInteger currentSelect = [self.allNotes indexPathForSelectedRow].row;
NSLog(#"Send is %lu",(unsigned long)currentSelect);
dvc.returnData =[self.fetchedObjects objectAtIndex:currentSelect];
NewClassNote *destViewController = segue.destinationViewController;
destViewController.comingData = [self.noteTitle objectAtIndex:[[self.allNotes indexPathForSelectedRow] row]];
destViewController.insertDate= [self.insertDates objectAtIndex:[[self.allNotes indexPathForSelectedRow] row]];
[self.allNotes reloadData];
}
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
#end
Can you explain to me why I get this error? The total rows after deletion is different than before deletion but I don't know why this errors?
You error goes from here:
self.fetchedObjects = (NSMutableArray *)[context executeFetchRequest:fetchRequest error:&error];
-executeFetchRequest:error: returns NSArray, it's immutable, if you just cast it to NSMutableArray it won't magically change itself. But later you try to
[_fetchedObjects removeObjectAtIndex:currentSelect];
which is sending -removeObjectAtIndex to an NSArray instance.
You can try to solve it like this:
self.fetchedObjects = [[context executeFetchRequest:fetchRequest error:&error] mutableCopy];
In my iOS app I need a tableview to be updated from another view. I have tried using NSNotifications but no success.The first view contains a tableview populated from core data using a fetch request. This view has also a Add button which opens a view to add objects to the core data entity.This second view has several text fields, a save button and a back button that opens the first view again, but the rows are not updated.
THis is the code from the first view controller:
#import "RootViewController.h"
#import "AddToDoViewController.h"
#interface RootViewController ()
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
#end
#implementation RootViewController
#synthesize fetchedResultsController, managedObjectContext,AddToDoButton;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setTitle:#"Today"];
[[self navigationItem] setRightBarButtonItem:[self editButtonItem]];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
- (void) viewWillAppear:(BOOL)animated{
[self.tableView reloadData];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
[[cell textLabel] setText:[[managedObject valueForKey:#"thingName"] description]];
[[cell detailTextLabel] setText:[[managedObject valueForKey:#"thingDescription"] description]];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
cell.textLabel.textColor = [UIColor blueColor];
cell.textLabel.font = [UIFont fontWithName:#"Noteworthy" size:16.0f];
cell.detailTextLabel.font = [UIFont fontWithName:#"Noteworthy" size:14.0f];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (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:#"Cell"] autorelease];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![context save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView
moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toIndexPath:(NSIndexPath *)destinationIndexPath;
{
NSMutableArray *things = [[fetchedResultsController fetchedObjects] mutableCopy];
// Grab the item we're moving.
NSManagedObject *thing = [[self fetchedResultsController] objectAtIndexPath:sourceIndexPath];
// Remove the object we're moving from the array.
[things removeObject:thing];
// Now re-insert it at the destination.
[things insertObject:thing atIndex:[destinationIndexPath row]];
// All of the objects are now in their correct order. Update each
// object's displayOrder field by iterating through the array.
int i = 0;
for (NSManagedObject *mo in things)
{
[mo setValue:[NSNumber numberWithInt:i++] forKey:#"displayOrder"];
}
[things release], things = nil;
[managedObjectContext save:nil];
}
#pragma mark -
#pragma mark Fetched results controller
- (IBAction)AddToDoAction:(id)sender {
AddToDoViewController *viewController = [[AddToDoViewController alloc] init];
[self presentViewController:viewController animated:YES completion:nil];
}
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController) return fetchedResultsController;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:#"FavoriteThing"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"displayOrder"
ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc]
initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil cacheName:#"ThingsCache"];
aFetchedResultsController.delegate = self;
[self setFetchedResultsController:aFetchedResultsController];
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
- (void)dealloc {
[fetchedResultsController release];
[managedObjectContext release];
[super dealloc];
}
#end
And this is the code from the second view controller
#import "AddToDoViewController.h"
#import "FavoriteThing.h"
#import "AppDelegate.h"
#import "RootViewController.h"
#interface AddToDoViewController ()
#end
#implementation AddToDoViewController
#synthesize ToDoDescriptionTextField,ToDoTextField,fetchedResultsController;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[ToDoTextField becomeFirstResponder];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)BackButtonAction:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)SaveButtonAction:(id)sender {
AppDelegate* appDelegate = [AppDelegate sharedAppDelegate];
NSManagedObjectContext* context = appDelegate.managedObjectContext;
NSManagedObject *favoriteThing = [NSEntityDescription insertNewObjectForEntityForName:#"FavoriteThing" inManagedObjectContext:context];
[favoriteThing setValue:#"ToDo 000250" forKey:#"thingName"];
[favoriteThing setValue:#"It sold out in eight days this year, you know?" forKey:#"thingDescription"];
[favoriteThing setValue:[NSNumber numberWithInt:0] forKey:#"displayOrder"];
NSError *error;
if(! [context save:&error])
{
NSLog(#"Whoopw,couldn't save:%#", [error localizedDescription]);
}
}
#end
Reload Your tableview in viewWillAppear.
-(void)viewWillAppear:(BOOL)animated
{
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[self.tableView reloadData];
}
Since you are using NSFetchedResultsController you should use it's delegate to update your table.
Otherwise you do not need to use a NSFetchedResultsController. For information on implementing NSFetchedResultsController delegate please see this link.
Declare this custom delegate in your addVC
#protocol AddViewControllerDelegate <NSObject>
-(void)AddPhotoViewController:(AddViewController *)addViewController store:(NSString *) data;
#end
and declare custom delegate as property variable in addVC
#property(strong, nonatomic) id <AddViewControllerDelegate> delegate;
In mainVC do this
while push addVC like this
AddPhotoViewController* addVC = [[AddPhotoViewController alloc]init];
addVC.delegate = self;
[self.navigationController pushViewController:addVC animated:YES];
-(void)AddPhotoViewController:(AddPhotoViewController *)addViewController store:(NSString *)data
{
[table_array addObject:data];
[self.tableView reloadData];
}
In another question of mine concerning the addition of an insert row in a UITableView backed by Core Data, I mentioned that my NSFetchedResultsController is assigning each object it fetches to a separate section in my UITableView. I assumed this was merely the default behavior, but Marcus S. Zarra said there might be something wrong with my configuration of the controller or my datasource delegate methods. I admit, my code feels a bit like Frankenstein with parts pulled from the Apple docs and numerous tutorials. This is my first program and my first time using Core Data, so please be gentle ;)
My table view controller's header is as follows:
#import <UIKit/UIKit.h>
#import "RubricAppDelegate.h"
#interface ClassList : UITableViewController {
NSMutableArray *classList;
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
}
#property(nonatomic,retain) NSMutableArray *classList;
#property(nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#property(nonatomic, retain) NSManagedObjectContext *managedObjectContext;
- (IBAction) grade:(id)sender;
#end
My implementation file includes a bunch of dummy test data. I included that in case I am using incorrect methods for instantiating the Core Data objects. Basically, I want to know if my NSFetchedResultsController should not be returning my objects (in this case, instances of myClass) into separate sections. If so, what am I doing to create that problem?
The ultimate goal at the moment is for me to be able to add an insert cell at the top of my table (I know that putting it at the bottom is "standard," but I like how it looks in the apps that do it the other way around). You will notice my -tableView:editingStyleForRowAtIndexPath: sets the cell style of section 0 to insert, but of course I need to figure out how to start the listing of myClass.classTitle at cell 1 instead of cell 0 (which is why I want to determine if having each object assigned to its own section is normal).
Here is my implementation file:
#import "ClassList.h"
#import "ClassRoster.h"
#import "RubricAppDelegate.h"
#import "Student.h"
#import "myClass.h"
#implementation ClassList
#synthesize classList;
#synthesize fetchedResultsController;
#synthesize managedObjectContext;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.editing = YES;
RubricAppDelegate *appDelegate = (RubricAppDelegate *)[[UIApplication sharedApplication] delegate];
managedObjectContext = [appDelegate managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"myClass" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entity];
//test data
myClass *newClass = (myClass *) [NSEntityDescription insertNewObjectForEntityForName:#"myClass" inManagedObjectContext:managedObjectContext];
newClass.classTitle = #"UFDN 1000";
NSNumber *ID = [NSNumber numberWithInt:1];
newClass.classID = ID;
Student *newStudent = (Student *) [NSEntityDescription insertNewObjectForEntityForName:#"Student" inManagedObjectContext:managedObjectContext];
newStudent.classID = ID;
newStudent.studentName = #"Andy Albert";
newStudent.studentUsername = #"albera";
[newClass addStudentsObject:newStudent];
newStudent.classID = ID;
newStudent.studentName = #"Bob Dole";
newStudent.studentUsername = #"doleb";
[newClass addStudentsObject:newStudent];
newStudent.classID = ID;
newStudent.studentName = #"Chris Hanson";
newStudent.studentUsername = #"hansoc";
[newClass addStudentsObject:newStudent];
myClass *newClass2 = (myClass *) [NSEntityDescription insertNewObjectForEntityForName:#"myClass" inManagedObjectContext:managedObjectContext];
newClass2.classTitle = #"UFDN 3100";
ID = [NSNumber numberWithInt:2];
newClass2.classID = ID;
newStudent.classID = ID;
newStudent.studentName = #"Danny Boy";
newStudent.studentUsername = #"boyd";
[newClass2 addStudentsObject:newStudent];
newStudent.classID = ID;
newStudent.studentName = #"James Matthews";
newStudent.studentUsername = #"matthj";
[newClass2 addStudentsObject:newStudent];
newStudent.classID = ID;
newStudent.studentName = #"Aaron Todds";
newStudent.studentUsername = #"toddsa";
[newClass2 addStudentsObject:newStudent];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"classID" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
NSError *error;
fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:#"classTitle" cacheName:nil];
[fetchedResultsController performFetch:&error];
UIBarButtonItem *gradeButton = [[UIBarButtonItem alloc]
initWithTitle:#"Grade"
style:UIBarButtonItemStylePlain
target:self
action:#selector(grade:)];
self.navigationItem.rightBarButtonItem = gradeButton;
[gradeButton release];
}
- (IBAction) grade:(id)sender {
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"Number of sections = %d", [[fetchedResultsController sections] count]);
return ([[fetchedResultsController sections] count]);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
id <NSFetchedResultsSectionInfo> myClass = [[fetchedResultsController sections] objectAtIndex:section];
NSLog(#"Number of classes = %d", [myClass numberOfObjects]);
return [myClass numberOfObjects];
}
// 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:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
myClass *theClass = [fetchedResultsController objectAtIndexPath:indexPath];
NSLog(#"Class name is: %#", theClass.classTitle);
cell.textLabel.text = theClass.classTitle;
}
return cell;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
return UITableViewCellEditingStyleInsert;
}
else return UITableViewCellEditingStyleDelete;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
myClass *result = (myClass *)[fetchedResultsController objectAtIndexPath:indexPath];
[managedObjectContext deleteObject:result];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
}
}
#pragma mark -
#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];
[detailViewController release];
*/
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc {
[classList release];
[super dealloc];
}
#end
My RubricAppDelegate is essentially identical to the Apple documentation for setting up Core Data NSManagedObjectContext, NSPersistentStoreCoordinator, etc. However, if you think there might be a problem in there, just let me know and I'll post it.
Edit: I forgot to mention two reasons I know each object is being assigned to a different section.
1) NSLog(#"Number of sections = %d", [[fetchedResultsController sections] count]); inside of -numberOfSectionsInTableView: returns the number of myClass objects I have.
2) If I set -numberOfSectionsInTableView: to return 1, my table only displays one object and cuts the rest out.
You have sections because you tell the fetched results controller to create them by passing a non-Nil value for sectionNameKeyPath: when you initialize the FRC.
Change:
fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:#"classTitle" cacheName:nil];
...to:
fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil cacheName:nil];
... and the sections will go away. Otherwise, the FRC will create one section for each value of the classTitle attribute in the store. If each myClass instance has a different value for classTitle each instance will have its own section in the tableview.