I am having a weird issue and need some help.
I am on a core data project and did not yet use a fetchedResultsController, just working with fetchRequets and arrays to populate zableviews. So now I decided to change and make use of FRC ...
Everything was pretty easy so far ... but with commitEditingStyle I am having issues since then - when deleting rows I am thrown an exception like this one:
The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update.
In the end I found out that it is because the object I want to delete remains in FRC ... I put some NSLog sections in liko so:
NSLog(#"Number before deleting: %i - deleting %#",[[fetchedResultsController fetchedObjects] count], [fetchedResultsController objectAtIndexPath:indexPath]);
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
NSLog(#"Number before saving: %i",[[fetchedResultsController fetchedObjects] count]);
NSError *error;
if (![context save:&error]) {
[NSException raise:NSGenericException format:#"Following error occured when trying to delete %#: %#", [fetchedResultsController objectAtIndexPath:indexPath], [error description]];
}
NSLog(#"Number after saving: %i",[[fetchedResultsController fetchedObjects] count]);
NSArray * cellsToDelete = [NSArray arrayWithObject:indexPath];
[tableView deleteRowsAtIndexPaths:cellsToDelete withRowAnimation:UITableViewRowAnimationFade];
The result was this:
2011-05-20 14:49:35.398 Nivellator[6000:207] Number before deleting: 3
2011-05-20 14:49:35.399 Nivellator[6000:207] Number before saving: 3
2011-05-20 14:49:35.404 Nivellator[6000:207] Number after saving: 3
Of course it will puke when I'm telling the tableview that it'll get 3 rows but only pass two ... but what's wrong here?
My old code was looking like this and worked without any issues ...
-(void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView isEqual:self.entityTableView] == YES) {
if (editingStyle != UITableViewCellEditingStyleDelete) {
return;
}
if ([self.entityArray count] <= indexPath.row) {
return;
}
Member *thisEntity = [self.entityArray objectAtIndex:indexPath.row];
[delegate.managedObjectContext deleteObject:thisEntity];
NSError *savingError = nil;
if ([delegate.managedObjectContext save:&savingError] == YES) {
// Remove the entity from the Array and delete the corresponding table cell with animation
//
[self.entityArray removeObject:thisEntity];
NSArray * cellsToDelete = [NSArray arrayWithObject:indexPath];
[tableView deleteRowsAtIndexPaths:cellsToDelete withRowAnimation:UITableViewRowAnimationFade];
} else {
/* Error handling missing */
}
}
}
OK
in the end it came down to RTFM ... so I made it partly work by changing the code such as:
-(void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView isEqual:self.entityTableView] == YES) {
if (editingStyle != UITableViewCellEditingStyleDelete) {
return;
}
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error;
if (![context save:&error]) {
[NSException raise:NSGenericException format:#"Following error occured when trying to delete %#: %#", [fetchedResultsController objectAtIndexPath:indexPath], [error description]];
}
if ([fetchedResultsController performFetch:&error]) {
[tableView beginUpdates];
NSArray * cellsToDelete = [NSArray arrayWithObject:indexPath];
[tableView deleteRowsAtIndexPaths:cellsToDelete withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
} else {
[NSException raise:NSGenericException format:#"Following error occured when trying to delete %#: %#", [fetchedResultsController objectAtIndexPath:indexPath], [error description]];
}
}
}
But when I'm using sectments in my FRC I still get the same error ... I cannot find anything more than this to do with the FRC ...
Any idea?
Delete the FRC's cache after the delete
Check that you have implemented the FRC's delegate methods properly.
Make sure you freeze the tableview with beginUpdates before you run the FRC's delegate methods.
Related
I'm using RestKit and RRNCollapsableTable. The problem is, when I load view for the first time, RestKit is downloading data from JSON. That delay causes menu to not load. What I'm trying to do is to make CollapsableTable wait for data.
[self requestData:^(BOOL success) {
if (success) {
_menu = [self buildMenu];
[self model];
}
}];
- (void)requestData:(void (^)(BOOL success))completionBlock {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Messages"];
NSSortDescriptor *byId = [NSSortDescriptor sortDescriptorWithKey:#"customNewsId" ascending:YES];
fetchRequest.sortDescriptors = #[byId];
NSError *error = nil;
// Setup fetched results
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext
sectionNameKeyPath:#"customNewsId"
cacheName:nil];
//[self.fetchedResultsController setDelegate:self];
BOOL fetchSuccessful = [self.fetchedResultsController performFetch:&error];
if (!fetchSuccessful) {
abort();
}
[[RKObjectManager sharedManager] getObjectsAtPath:#"api/json/get/bZmroLaBCG" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
RKLogInfo(#"Load complete: Table should refresh...");
//[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:#"LastUpdatedAt"];
//[[NSUserDefaults standardUserDefaults] synchronize];
NSError *error = nil;
if ([[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext hasChanges] && ![[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext saveToPersistentStore:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
completionBlock(YES);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"Load failed with error: %#", error);
completionBlock(NO);
}];
completionBlock(YES);
}
Then BuildMenu is just iterating over fetched objects and put them in section.
-(NSArray *)buildMenu {
__block NSMutableArray *collector = [NSMutableArray new];
NSInteger sections = [self.fetchedResultsController.sections count];
for (NSInteger i = 0; i < sections; i++) {
Messages *message = [_fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:i]];
MenuSection *section = [MenuSection new];
section.items = #[message.message,message.pushNotificationMessage];
section.title = message.title;
NSLog(#"section.title - %#",section.title);
[collector addObject:section];
}
return [collector copy];
}
Method model is responsible for DataSource for CollapsableTable.
-(NSArray *)model {
return _menu;
}
Thanks in advance for any help.
Greetings.
I have several CoreDataTableViewControllers that utilize the helper class from Paul Hegarty's course. Everyone of them works except this one, and I cannot see a difference.
When the table first comes up, it is correctly populated and the segue executes properly when a cell is selected. However when I hit the back button, the table displays (null), (null) everywhere.
I have tried every variant of calling [self useDocument] that I can think of, still to no avail. Any thoughts? Thanks in advance.
//
// TeamTableViewController.m
//
#import "TeamTableViewController.h"
#import "iTrackAppDelegate.h"
#import "CoreDataTableViewController.h"
#import "SchoolRecords.h"
#import "ScheduleViewController.h"
#interface TeamTableViewController ()
#property NSInteger toggle;
#end
#implementation TeamTableViewController
#synthesize iTrackContext = _iTrackContext;
#synthesize schoolSelected = _schoolSelected;
-(void) setSchoolSelected:(SchoolRecords *)schoolSelected
{
_schoolSelected = schoolSelected;
}
-(void) setITrackContext:(NSManagedObjectContext *)iTrackContext
{
if(_iTrackContext != iTrackContext){
if (!iTrackContext) {
MyCoreDataHandler* cdh =
[(iTrackAppDelegate *) [[UIApplication sharedApplication] delegate] cdh];
_iTrackContext = cdh.context;
} else {
_iTrackContext = iTrackContext;
}
}
[self useDocument];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)setupFetchedResultsController // attaches an NSFetchRequest to this UITableViewController
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"SchoolRecords"];
// no predicate because we want ALL the Athletes
request.sortDescriptors = [NSArray arrayWithObjects:
[NSSortDescriptor sortDescriptorWithKey:#"schoolName" ascending:YES],
nil];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.iTrackContext
sectionNameKeyPath:nil
cacheName:nil];
__block NSInteger myCount;
int64_t delayInSeconds = 5.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self.iTrackContext performBlock:^(void){NSError* requestError = nil;
myCount = [self.iTrackContext countForFetchRequest:request error:&requestError];
NSLog(#"In %# and count of iTrackContext = %lu", NSStringFromClass([self class]),(unsigned long)myCount);
}];
if (!myCount || myCount == 0) {
[self displayAlertBoxWithTitle:#"No Teams" message:#"Have you added athletes yet? \nPlease go to Add Athletes" cancelButton:#"Okay"];
}
});
}
- (void)useDocument
{
if (self.iTrackContext) {
[self setupFetchedResultsController];
} else {
NSString* errorText = #"A problem arose opening the search results database of Athletes.";
[self displayAlertBoxWithTitle:#"File Error" message:errorText cancelButton:#"Okay"];
}
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!self.iTrackContext) {
MyCoreDataHandler* cdh =
[(iTrackAppDelegate *) [[UIApplication sharedApplication] delegate] cdh];
[self setITrackContext:cdh.context];
} else {
NSLog(#"In %# of %#. Getting ready to call useDocument",NSStringFromSelector(_cmd), self.class);
[self useDocument];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// If divide into sections use line below otherwise return 1.
// return [[self.fetchedResultsController sections] count];
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Do not really need this with only one section, but makes code usable if add sections later.
return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"teamInformation";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
SchoolRecords *schoolResults = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString* titleText = schoolResults.schoolName;
cell.textLabel.text = titleText;
cell.detailTextLabel.text = [NSMutableString stringWithFormat:#"%#, %#", schoolResults.schoolCity, schoolResults.schoolState];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
# pragma navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
[self setSchoolSelected:[self.fetchedResultsController objectAtIndexPath:indexPath]];
// be somewhat generic here (slightly advanced usage)
// we'll segue to ANY view controller that has a photographer #property
if ([segue.identifier isEqualToString:#"scheduleDetailSegue"]) {
// use performSelector:withObject: to send without compiler checking
// (which is acceptable here because we used introspection to be sure this is okay)
NSLog(#"Preparing to passing school with schoolID = %#", self.schoolSelected.schoolID);
[segue.destinationViewController convenienceMethodForSettingSchool:self.schoolSelected];
}
}
- (void) displayAlertBoxWithTitle:(NSString*)title message:(NSString*) myMessage cancelButton:(NSString*) cancelText
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
message:myMessage
delegate:nil
cancelButtonTitle:cancelText
otherButtonTitles:nil];
[alert show];
}
#end
Well, I am not certain what the problem was. I ended up deleting the "offending" TableViewControllers in StoryBoard and recreated them. That did the trick. In retrospect, I wonder if I did not specify the wrong type of segue from my tabViewController. But I deleted it before I thought of that possibility.
I have a UITableView populated by data parsed from xml. The parsing works but the table remains blank.
The console shows that the xml form the url is parsed and shows its components. It also shows the number of objects that the rows of tableview should have when asked in a different function but the numberOfRowsInSection: is returning Null. Therefore, the tableView in the Simulator remains blank.
Here is my code. It is simple code from a tutorial:
+++++++++++++++++ RootViewController.h++++++++++++++++++++++
#import < UIKit/UIKit.h >
#interface RootViewController : UITableViewController < NSXMLParserDelegate >{
IBOutlet UITableView *newsTable;
UIActivityIndicatorView *activityIndicator;
CGSize cellSize;
NSXMLParser *rssParser;
NSMutableArray *stories;
NSMutableDictionary *item;
NSString *currentElement;
NSMutableString *currentTitle, *currentDate, *currentSummary, *currentLink;
}
#property (nonatomic, retain) NSMutableArray *stories;
#property (nonatomic, retain) IBOutlet UITableView *newsTable;
-(void)parseXMLFileAtURL:(NSString *)URL;
#end
+++++++++++++++++++++++++++ RootViewController.m ++++++++++++++++++++++++++++++++++++++
#import "RootViewController.h"
#implementation RootViewController
#synthesize newsTable, stories;
-(void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[newsTable reloadData];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if([stories count] == 0){
NSString *path = #"http://feeds.feedburner.com/TheAppleBlog";
[self parseXMLFileAtURL:path];
}
cellSize = CGSizeMake([newsTable bounds].size.width, 60);
}
// Customize the number of sections in the table view.
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(void)parseXMLFileAtURL:(NSString *)URL {
stories = [[NSMutableArray alloc] init];
NSURL *xmlURL = [NSURL URLWithString:URL];
rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[rssParser setDelegate:self];
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
-(void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(#"Found file and started parsing");
}
-(void) parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
NSString *errorString = [NSString stringWithFormat:#"Unable to download story feed from the website (error code %i)", [parseError code]];
NSLog(#"error parsing XML: %#", errorString);
UIAlertView *errorAlert = [[UIAlertView alloc]:#"Error loading content" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitle:nil];
[errorAlert show];
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NSLog(#"Found this Element %#", elementName);
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc] init];
currentTitle = [[NSMutableString alloc] init];
currentDate = [[NSMutableString alloc] init];
currentSummary = [[NSMutableString alloc] init];
currentLink = [[NSMutableString alloc] init];
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog(#"End this Element %#", elementName);
if ([elementName isEqualToString:#"item"]) {
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentLink forKey:#"link"];
[item setObject:currentSummary forKey:#"summary"];
[item setObject:currentDate forKey:#"date"];
[stories addObject:[item copy]];
NSLog(#"adding Story : %#",currentTitle);
}
}
// Customize the number of rows in the table view.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Count is = %#", [stories count]);
return [stories count];
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
NSLog(#"Found characters: %#", string);
if([currentElement isEqualToString:#"title"]){
[currentTitle appendString:string];
NSLog(#"The Title is : %#", currentTitle);
}
else if([currentElement isEqualToString:#"link"]){
[currentLink appendString:string];
NSLog(#"The Link is : %#", currentLink);
}
else if([currentElement isEqualToString:#"description"]){
[currentSummary appendString:string];
NSLog(#"The summary is : %#", currentSummary);
}
else if([currentElement isEqualToString:#"pubDate"]){
[currentDate appendString:string];
NSLog(#"The Date is : %#", currentDate);
}
}
-(void)parserDidEndDocument:(NSXMLParser *)parser{
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
NSLog(#"Stories array has %d items", [stories count]);
NSLog(#"Stories are : %#",stories);
}
// Customize the appearance of table view cells.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
// Configure the cell.
cell.textLabel.text = (NSString *)[[stories objectAtIndex:indexPath.row] objectForKey:#"title"];
return cell;
}
-(void)dealloc {
[super dealloc];
[newsTable release];
[currentDate release];
[currentElement release];
[currentSummary release];
[currentLink release];
[stories release];
[item release];
[currentTitle release];
[rssParser release];
}
You have to tell the table view that there is new data by calling reloadData after you have parsed the XML.
Is the newsTable outlet properly connected to the table view in IB? And, is the table's dataSource outlet set to your view controller?
To expand on #omz's correct answer:
The method numberOfRowsInSection is not returning NULL but zero. (In Objective-C, nil==zero and Null is a singleton object.)
The only reason that it would return zero is if the [stories count] returns zero and the only reason [stories count] would return zero is if it has no elements. Since you've confirmed that the parse works and stories has elements, then the tableview must be seeking data before the parse occurs.
This method is called first and it is the only place you reload data:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[newsTable reloadData];
// You trigger the tableview to call numberOfRowsInSection before stories is populated.
}
This method is called only after the tableview has appeared on screen and it is only after the tableview appears that you populate stories.
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if([stories count] == 0){
NSString *path = #"http://feeds.feedburner.com/TheAppleBlog";
[self parseXMLFileAtURL:path];
}
cellSize = CGSizeMake([newsTable bounds].size.width, 60);
}
However, nothing triggers the tableview to call numberOfRowsInSection again so the tableview remains blank. Simply moving the populating of stories to viewWillAppear: will fix the problem.
Each time you alter the data upon which the tableview depends (regardless of reason) you must call reloadData otherwise the tableview remains unaware that it no longer displays the current data set.
As an aside, you should use the dot notation when referring to properties to ensure they are properly retained. You should use self.stories to refer to the stories property. Otherwise, it might be released at random causing an equally random crash.
I have created one application with core data but is unable to display the data in table view. I am writing the code below which I have written for fetching the results:
#import "RootViewController.h"
#import "DetailViewController.h"
#import "AddViewController.h"
#import "EmployeeDetailsAppDelegate.h"
/*
This template does not ensure user interface consistency during editing operations in the table view. You must implement appropriate methods to provide the user experience you require.
*/
#interface RootViewController ()
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
#end
#implementation RootViewController
#synthesize detailViewController, fetchedResultsController, managedObjectContext;
#synthesize array;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
// EmployeeDetailsAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
self.title = #"Employee Name";
self.navigationItem.rightBarButtonItem = self.editButtonItem;
NSMutableArray *tempArr = [[NSMutableArray alloc]initWithCapacity:0];
if (self.fetchedResultsController) {
tempArr = self.fetchedResultsController.fetchedObjects;
}
self.array = tempArr;
[super viewDidLoad];
[tempArr release];
}
- (void)viewWillAppear:(BOOL)animated {
[self.tableView reloadData];
[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 {
// Ensure that the view controller supports rotation and that the split view can therefore show in both portrait and landscape.
return YES;
}
#pragma mark -
#pragma mark Add a new object
- (void)insertNewObject:(id)sender {
AddViewController *add = [[AddViewController alloc]initWithNibName:#"AddViewController" bundle:nil];
self.modalPresentationStyle = UIModalPresentationFormSheet;
add.wantsFullScreenLayout = NO;
[self presentModalViewController:add animated:YES];
[add release];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if([self.array count])
{
return [array count];
}
return 1;
}
- (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];
}
// Configure the cell.
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
-(void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath{
AddViewController *detail = [fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = detail.empName.text;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the managed object.
NSManagedObject *objectToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
if (self.detailViewController.detailItem == objectToDelete) {
self.detailViewController.detailItem = nil;
}
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error;
if (![context save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// The table view should not be re-orderable.
return NO;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Set the detail item in the detail view controller.
detailViewController = [[DetailViewController alloc]initWithStyle:UITableViewStylePlain];
AddViewController *selectedName = (AddViewController *)[[self fetchedResultsController]objectAtIndexPath:indexPath];
detailViewController.detail = selectedName;
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
#pragma mark -
#pragma mark Fetched results controller
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Details" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"EmployeeName" ascending:NO];
NSSortDescriptor *idDescriptor = [[NSSortDescriptor alloc] initWithKey:#"EmployeeID" ascending:NO];
NSMutableArray *sortDescriptors = [[NSMutableArray alloc] initWithObjects:nameDescriptor, idDescriptor, nil];
self.array = sortDescriptors;
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[nameDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
#pragma mark -
#pragma mark Fetched results controller delegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
#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 {
self.fetchedResultsController = nil;
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
self.array = nil;
}
- (void)dealloc {
[array release];
[detailViewController release];
[fetchedResultsController release];
[managedObjectContext release];
[super dealloc];
}
#end
The problem is I am getting a warning with the following line:
tempArr = self.fetchedResultsController.fetchedObjects;
The warning is: "/Users/satyam/Desktop/EmployeeDetails/Classes/RootViewController.m:43:0 /Users/satyam/Desktop/EmployeeDetails/Classes/RootViewController.m:43: warning: incompatible Objective-C types assigning 'struct NSArray *', expected 'struct NSMutableArray *'"
Just read the warning word for word.
you try to assign an NSArray to a variable that expects a NSMutableArray.
self.fetchedResultsController.fetchedObjects is an NSArray
tempArr is an NSMutableArray
but if you use the NSFetchedResultsController you don't need your own data array at all.
The NSFetchedResultsController handles all the data for you.
so maybe you want to replace
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if([self.array count])
{
return [array count];
}
return 1;
}
with
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
your own datasource is invalid anyway. because you assign the sortDescriptor used for the NSFetchedResultsController to it.
NSMutableArray *sortDescriptors = [[NSMutableArray alloc] initWithObjects:nameDescriptor, idDescriptor, nil];
self.array = sortDescriptors;
I don't know what you wanted to achieve by doing this.
i can parse data and see the output also but i am not able to display them in table view
problem is 1st my tableviews code are executing then rest functions are working that's why i am getting 0 , how to avoid this ??
this is my code
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#" value %d",[jsonArray count]);// always 0
return [jsonArray count];
}
in this method also i am getting 0 valuee
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath { NSDictionary *aTweet = [jsonArray objectAtIndex:[indexPath
row]]; NSLog(# " divy is
%#",aTweet);// nothing
}
other codes
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
NSDictionary *data = (NSDictionary *) [json objectWithString:responseString error:nil];
NSDictionary *menu = (NSDictionary *) [data objectForKey:#"name"];
//label.text=[dict objectForKey:#"firstName"];
// parsing all the items in to the NSArray
NSArray *items = (NSArray *) [menu objectForKey:#"phoneNumber"];
int ndx;
//NSDictionary *stream;
for (ndx = 0; ndx< items.count; ndx++) {
stream = (NSDictionary *)[items objectAtIndex:ndx];
NSLog(#"This is the title of a stream: %#", [stream valueForKey:#"type"]);
[jsonArray addObject:stream];
}
NSLog(#" aray is %#",jsonArray);// show all data working
NSLog(#" sterab is %#",[stream valueForKey:#"home"]);// this is also working
and this is my view did load()
- (void)viewDidLoad {
jsonArray= [[NSMutableArray alloc] init] ;
[super viewDidLoad];
responseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://Json/Number.json"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
label.text = [NSString stringWithFormat:#"Connection failed: %#", [error description]];
}
Possibly, the problem is that you data doesn't load immediately. And UITableView, when created, stores necessary data in some sort of cache. This allows to avoid often calls of data source's methods, like tableView:numberOfRowsInSection: and others. So you should explicitly call UITableView's reloadData method to refresh table.
To solve the problem, you should do something like this:
In viewDidLoad just show some spinner to indicate program activity.
In connectionDidFinishLoading: after all data was initialized, call [yourTableView reloadData].