0

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?

AeroX
  • 3,387
  • 2
  • 25
  • 39
Mr.Geeker
  • 395
  • 3
  • 13
  • Try remove [self.allNotes reloadData] at the last line of commitEditingStyle(). – ljk321 Dec 24 '14 at 11:24
  • hey , i got same error -[_PFArray removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fa039cf0570 – Mr.Geeker Dec 24 '14 at 11:26
  • In addition to the answer below, it seems that you only delete the data but keep the table row. You may want to add something like this.`[myTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; ` – ljk321 Dec 24 '14 at 11:34
  • @Mr.Geeker You are trying to remove object from Immutable array, that is why your app goes crash after deleting object from fetchedObjects Nsarray. – Sandeep Ahuja Dec 24 '14 at 11:44
  • Can you update my code because i tried most of solution but not working – Mr.Geeker Dec 24 '14 at 11:51

1 Answers1

4

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];
MANIAK_dobrii
  • 6,014
  • 3
  • 28
  • 55
  • still same problem , i have tried this before . this problem make me crazy . – Mr.Geeker Dec 24 '14 at 11:49
  • There's one more in viewWillAppear:. Take my advise: refactor your code and don't tweak your code here there trying to make it work magically. – MANIAK_dobrii Dec 24 '14 at 11:53
  • Thanks you are right but can you explain me what dose mean mutableCopy – Mr.Geeker Dec 24 '14 at 11:56
  • @Mr.Geeker http://stackoverflow.com/a/2002263/1032151 In short: if API creators follow conventions (i.e. most likely, or like 99% of time), you'll get a "mutable version" of an object. NSMutableArray from NSArray, NSMutableString from NSString etc. Note, that it depends on implementation. But if you're working with Foundation framework you may consider it to be true. – MANIAK_dobrii Dec 24 '14 at 12:07
  • in addition to MANIAK's suggest you can try one more thing. Delete the object from array, delete the cell & then delete the object from context. Offcourse try this only if you don't succeed after doing MANiAK suggest. – Dinakar Dec 24 '14 at 12:12
  • Looking at your solution I feel you can achieve it in a even better/smart way. Introduce NSFetchResultController with your predicate and implement NSFetchResultControllerDelegate Methods. if you delete an object from context one of the delegate methods gets triggered where you would delete the particular row (Hence avoiding a complete reloading of the tableView). – Dinakar Dec 24 '14 at 12:15
  • @downwoter: not sure why, but I guess that's because the solution is not perfect, right? There's a lot of stuff to fix in the asker's code, I'm not going to fix it or improve anyhow, I've just helped to fix the exact problem. If there's something else I can't see - comment. – MANIAK_dobrii Dec 26 '14 at 14:10