简体   繁体   中英

predicateWithFormat returns wrong Core data object

My application contains image object that it receives from a server and is sotred in Core data. Each object contains image = NSData imageId = NSString and a imageKeyword = NSString To check if any images have been removed from the server the application receives a array of image_id that is compares with the image_ids containing in the application and deletes any images that aren't found in the array from the server.

The method uses NSPredicate to find if imageId are found in allImageArray that the application receives from the server. Objects that are not found are added to imageToDelete array and then removed from core data. So long as the objects only contains imageId and image this method works fine.

-(void)updateLocalImagesFromActivitiesParents:(NSArray*)allImageArray
{
    NSPredicate *imageIdsFilter = [NSPredicate predicateWithFormat:@"NOT (imageId IN %@)", allImageArray];
    NSFetchRequest *imageIdsRequest = [ImageCD MR_requestAllWithPredicate:(NSPredicate *)imageIdsFilter];
    NSArray *imagesToDelete = [ImageCD MR_executeFetchRequest:imageIdsRequest];


    if([imagesToDelete count] > 0){
    [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext){

        for(ActivityCD *imageToDelete in imagesToDelete){
            [imageToDelete MR_deleteEntityInContext:localContext];
            [localContext MR_saveToPersistentStoreAndWait];

        }
    }];
    }
}

But I noticed that each time I assign a value to imageKeyword the above method detect is as not found in the allImageArray and deletes it. I have a hard time understanding why this happens because the delete method should only look for imageid but seems to detect changes in imageKeyword too.

Sample from the log of a object that is deleted. As mentioned the ImageId =25245 are found in the allImageArray from the server and are only deleted when I add "word" to imageKeyword.

"<ImageCD: 0x600003464c80> (entity: ImageCD; id: 0xa0c6b9257bed7492 <x-coredata://6454DD11-CEDB-40C2-B5E0-1FEE8006EE92/ImageCD/p26> ; data: {\n    image = <89504e47 0d0a1a0a 0000000d 49484452 00000280 00000203 08020000 001b8b38 02000020 00494441 54789c84 bd4982e5 b8ae>;\n    imageId = 25245;\n    imageKeyword = word;\n})"

Here is the method I assign a imageKeyWord to the object.

-(void)setImageKeyWord
{
    ImageCD *localImage = [ImageCD MR_findFirstByAttribute:@"imageId" withValue:[NSString stringWithFormat:@"%@", _choosenImageId]];

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext * _Nonnull localContext) {

    localImage.imageKeyword = _userCreate;


    }];
    [self testingKeyWordSearch];

}

I´m guessing I'm somehow assigning the imagKeyWord wrong but I cannot figure out how. Would appreciate some support :)

-(void)setImageKeyWord
{
    [MagicalRecord saveWithBlock:^(NSManagedObjectContext * _Nonnull localContext) {
        ImageCD *localImage = [ImageCD MR_findFirstByAttribute:@"imageId"
                                                     withValue:[NSString stringWithFormat:@"%@", _choosenImageId]
                                                     inContext:localContext];
        localImage.imageKeyword = _userCreate;
    }];
    [self testingKeyWordSearch];
}

In your code, you call findFirstByAttribute . It returns an instance of ImageCD on the defaultContext .

When you change the value of imageKeyword you are changing it on the defaultContext . Not in the localContext that is available in saveWithBlock .

When your saveWithBlock completes, you've saved nothing! The next time the defaultContext saves your change to localImage will be persisted.

Easily fixed. Just call findFirstByAttribute within saveWithBlock and use the localContext . When saveWithBlock completes it will merge the localContext into the defaultContext .

To be safe, I would change your first block of code so all fetching and deleting are on the same context:

-(void)updateLocalImagesFromActivitiesParents:(NSArray*)allImageArray
{
    NSPredicate *imageIdsFilter = [NSPredicate predicateWithFormat:@"NOT (imageId IN %@)", allImageArray];

    if([imagesToDelete count] > 0){
    [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext){

        NSFetchRequest *imageIdsRequest = [ImageCD MR_requestAllWithPredicate:(NSPredicate *)imageIdsFilter inContext:localContext];
        NSArray *imagesToDelete = [ImageCD MR_executeFetchRequest:imageIdsRequest inContext:localContext];

        for(ActivityCD *imageToDelete in imagesToDelete){
            [imageToDelete MR_deleteEntityInContext:localContext];
            [localContext MR_saveToPersistentStoreAndWait];

        }
    }];
    }
}  

You should probably read MagicalRecord & Apple docs about NSManagedObjectContext . Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM