views:

140

answers:

1

I am wondering how I could delete an object depending on it's title for the CoreData 'name' property I have. To Add an Object I use this code:

NSManagedObjectContext *moc = [self managedObjectContext];
JGManagedObject *theParent = 
    [NSEntityDescription insertNewObjectForEntityForName:@"projects"
                                  inManagedObjectContext:moc];
[theParent setValue:nil forKey:@"parent"];
// This is where you add the title from the string array
[theParent setValue:@"myTitle" forKey:@"name"]; 
[theParent setValue:[NSNumber numberWithInt:0] forKey:@"position"];

But I can't seem to find an equivalent function to remove An object.

A: 

I don't know if you looked in the Core Data Programming guide in the section for adding and deleting objects.

Edit

I've modified this to delete from an array of names. Again; less then 5 minutes work with the Predicate Programming Guide.

- (void)removeObjectsWithNames:(NSArray *)nameArray {
    // Get the moc and prepare a fetch request for the required entity
    NSManagedObjectContext *moc = [self managedObjectContext];
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Project" inManagedObjectContext:moc];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDescription];

    // Create a predicate for an array of names.
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name IN %@", nameArray];
    [request setPredicate:predicate];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

    // Execute the fetch request put the results into array
    NSError *error = nil;
    NSArray *resultArray = [moc executeFetchRequest:request error:&error];
    if (resultArray == nil)
    {
        // Diagnostic error handling
        NSAlert *anAlert = [NSAlert alertWithError:error];
        [anAlert runModal];
    }

    // Enumerate through the array deleting each object.
    // WARNING, this will delete everything in the array, so you may want to put more checks in before doing this.
    For (JGManagedObject *objectToDelete in resultArray ) {
        // Delete the object.
        [moc deleteObject:objectToDelete];
    }
}

Edited 10/10/2009 - To add what Joshua has tried.

for(NSString *title in oldTasks) { // 1
    // Get the moc and prepare a fetch request for the required entity
    NSManagedObjectContext *moc = [self managedObjectContext];
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"projects" inManagedObjectContext:moc];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDescription];

    // Create a predicate for an array of names.
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"title IN %d", oldTasks]; // 2
    [request setPredicate:predicate];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

    // Execute the fetch request put the results into array
    NSError *error = nil;
    NSArray *resultArray = [moc executeFetchRequest:request error:&error];
    if (resultArray == nil)
    {
        // Diagnostic error handling
        NSAlert *anAlert = [NSAlert alertWithError:error];
        [anAlert runModal];
    }

    JGManagedObject *objectToDelete = [resultArray objectAtIndex:0];
    // Delete the object.
    [moc deleteObject:objectToDelete];
}

Notes

I've highlighted two lines.

  1. You've pasted my example as a for loop rather than a function call. This is just taking the strings off one at a time and passing them into the method. In my example, I'm passing in an array of strings that you want to match.

  2. This is where you are having your problem. If you'd bothered reading the the Predicate Programming Guide, right at the top, in the Predicates Basics section it says it expects the class that it is being used with should be KVC compliant. This is why you are getting the error about KVC compliance. You are trying to search for title IN... but title isn't a property of your model.

I think you may be confused about what a predicate does. Look at the exaple code that I wrote.

Firstly, I create a Fetch request which will select objects from the 'Projects' entity.

Secondly, I create a predicate which says for each object returned by the fetch request, get the value of the 'name' property and compare it to the values of the objects in the 'namesArray'

Thirdly, I'm creating a sort descriptor that will sort the results in ascending order based on the 'name' property.

Then, once I've set this fetch request up, I run it against the moc and it returns an array of objects that match these criteria.

Abizern
Thanks, That's just what I'm looking for. I am trying to delete more than one object so like you said it will be a bit harder. Where would I start with this?
Joshua
Ah, Ok, That helps. This is the code I'm using http://grab.by/8He. It loops through an array of strings and hopefully deleting the objects which have a title matching any in the array. But it seems to throw a load of errors, http://grab.by/8Hf, http://grab.by/8Hg. It says that the Class is not KVC Compliant. But i am unsure what it's talking about.
Joshua
@Joshua: Those screen grabs are going to disappear in a week, which won't make this helpful for anyone else who has the same problem. Firstly, you've copied and pasted my method definition as a for loop. Secondly, that's not a load of errors, that's the call stack for the single error which shows you the method calls that lead to the problem. Thirdly; you're trying to create a predicate based on the property title, which doesn't exist in your model.
Abizern
Ok. I want the predicate to be based on the string in a Array not a property.
Joshua
The other way around; it's expecting a property called title, which it can't find in your model.
Abizern
I have an array of strings and I want the Predicate to be the Title of one of the strings, that why I am looping through it.
Joshua
You don't have to loop through it the way you are doing. You pass the array of strings you want to search for directly to the predicate when you create it.
Abizern
Ok. You were right I wasn't sure what Predicate meant. I am now using this code ( grab.by/8IW )(Don't worry about the errors is just saying they have been re-declared because I declared them earlier) without looping through the array of names only the objects. However, in the Action I have written to the NSLog and have found that the Action is stuck in a loop as the Logs keep appearing over and over again.
Joshua
Have you tried putting breakpoints in your code to see what is calling this repeatedly?
Abizern
Don't worry I have fixed the looping now.
Joshua
Nope, I haven't. I'll put in some breakpoints.
Joshua
Ok. I've put in Breakpoints in the whole IBAction. As you many now the action is to sync with the Calendar store. This is what Happens the first two times I sync it works, then the third time it loops. When it gets to the end of the action it skips to another action which is used for KVO and which triggers the Sync IBAction ( http://grab.by/8Ji ), this is the method that gets stuck, it keeps looping through it thus triggering the Sync IBAction over and over again. Why would it do this?
Joshua
No idea. Sorry. I can't figure out what's going on inside a function call just from the declaration. And anyway - that's a whole different problem.
Abizern
No worries, Like you said it's a whole different problem so I have accepted your answer and started a new question concerning the new problem I have. :)
Joshua