predicateWithFormat 返回错误的核心数据对象

Posted

技术标签:

【中文标题】predicateWithFormat 返回错误的核心数据对象【英文标题】:predicateWithFormat returns wrong Core data object 【发布时间】:2018-10-25 13:03:05 【问题描述】:

我的应用程序包含从服务器接收并存储在核心数据中的图像对象。每个对象包含 image = NSData imageId = NSString 和 imageKeyword = NSString 为了检查是否有任何图像已从服务器中删除,应用程序接收一个 image_id 数组,该数组与应用程序中包含的 image_ids 进行比较,并从服务器中删除数组中未找到的任何图像。

该方法使用 NSPredicate 来查找应用程序从服务器接收的 allImageArray 中是否找到 imageId。未找到的对象被添加到 imageToDelete 数组中,然后从核心数据中删除。只要对象仅包含 imageId 和 image,此方法就可以正常工作。

-(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];

        
    ];
    

但我注意到,每次我为 imageKeyword 分配一个值时,上述方法检测在 allImageArray 中找不到并删除它。我很难理解为什么会发生这种情况,因为 delete 方法应该只查找 imageid 但似乎也能检测到 imageKeyword 的变化。

已删除对象的日志中的示例。如前所述,ImageId =25245 在服务器的 allImageArray 中找到,并且仅在我将“word”添加到 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)"

这是我为对象分配 imageKeyWord 的方法。

-(void)setImageKeyWord

    ImageCD *localImage = [ImageCD MR_findFirstByAttribute:@"imageId" withValue:[NSString stringWithFormat:@"%@", _choosenImageId]];

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext * _Nonnull localContext) 

    localImage.imageKeyword = _userCreate;


    ];
    [self testingKeyWordSearch];


我猜我以某种方式分配了 imagKeyWord 错误,但我不知道怎么做。希望得到一些支持:)

【问题讨论】:

【参考方案1】:
-(void)setImageKeyWord

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

在您的代码中,您调用findFirstByAttribute。 它在defaultContext 上返回ImageCD 的实例。

当您更改imageKeyword 的值时,您将在defaultContext 上更改它。不在localContext 中,在saveWithBlock 中可用。

当您的saveWithBlock 完成时,您什么也没有保存!下次defaultContext 将您的更改保存到localImage 时将被保留。

很容易修复。只需在saveWithBlock 中调用findFirstByAttribute 并使用localContext。当saveWithBlock 完成时,它会将localContext 合并到defaultContext

为了安全起见,我会更改您的第一个代码块,以便所有获取和删除都在同一个上下文中:

-(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];

        
    ];
    
  

您可能应该阅读有关 NSManagedObjectContext 的 MagicalRecord 和 Apple 文档。祝你好运!

【讨论】:

以上是关于predicateWithFormat 返回错误的核心数据对象的主要内容,如果未能解决你的问题,请参考以下文章

predicateWithFormat 很慢

NSPredicate - predicateWithFormat 不安全

用于电子邮件问题的 NSPredicate predicateWithFormat

如何使用 predicateWithFormat 查询 NSString 包含在 NSSet 中

+[NSPredicate predicateWithFormat] 替换保留字

NSPredicate predicateWithFormat 导致异常