NSBatchUpdateRequest未保存可转换属性

时间:2018-01-22 19:23:32

标签: ios objective-c core-data nsbatchdeleterequest nsbatchupdaterequest

我有一个实体(TestEntity),其中包含一个“Transformable”属性,该属性包含一个对象(MyObjectClass)。初始加载时,可转换保存正确;初始化如下:

TestEntity *test = (TestEntity *)[NSEntityDescription insertNewObjectForEntityForName:ENTITY[<Int>] inManagedObjectContext:temporaryContext];
test.transformableAttr = [[MyObjectClass alloc] initWithObject:obj];

但是,当我获取一个对象(我用NSDictionaryResultType作为字典获取)并更新其“Transformable”属性时,

MyObjectClass *my_obj = ....
dict[@"transformableAttr"] = my_obj

它成功保存,但当我再次获取它时,我获得nil“Transformable”属性。

现在这只发生在“NSBatchUpdateRequest”中,因为当我使用MOC保存时

TestEntity *test = ....
test.transformableAttr = updated_object

它成功保存,我可以在再次提取时访问更新的属性。

任何人都可以解释一下吗?这是否意味着NSBatchUpdateRequest不可转换?

我的NSBatchUpdateRequest代码:

[context performBlock:^{
    NSError *requestError               = nil;
    NSBatchUpdateRequest *batchRequest  = [NSBatchUpdateRequest batchUpdateRequestWithEntityName:entity];
    batchRequest.resultType             = NSUpdatedObjectIDsResultType;
    batchRequest.propertiesToUpdate     = properties;
    NSBatchUpdateResult *result         = nil;
    SET_IF_NOT_NIL(batchRequest.predicate, predicate)

    @try {
        result = (NSBatchUpdateResult *)[context executeRequest:batchRequest error:&requestError];
        if (requestError != nil){
            // @throw
        }

        if ([result.result respondsToSelector:@selector(count)]){
            __block NSInteger counter = [result.result count];

            if (counter > 0){
                [managedObjectContext performBlock:^{

                    for(NSManagedObjectID *objectID in result.result){
                        NSError *faultError = nil;
                        NSManagedObject *object = [managedObjectContext existingObjectWithID:objectID error:&faultError];

                        if (object && faultError == nil) {
                            [managedObjectContext refreshObject:object mergeChanges:YES];
                        }

                        counter--;
                        if (counter <= 0) {
                            // complete
                        }
                        else{
                            // Wait.
                        }
                    }
                }];
            }
            else{
                // No Changes
            }
        }
        else {
            // No Changes
        }
    }
    @catch (NSException *exception) {
        @throw;
    }
}];

1 个答案:

答案 0 :(得分:0)

文档似乎没有提到这个特定情况,但我并不感到惊讶它不起作用。 NSBatchUpdateRequest被描述为[强调我的]:

  

请求Core Data在持久存储中批量更新数据,而不将任何数据加载到内存中

Transformables通过在内存中转换为Data来实现。如果您的类符合NSCoding,则编码/解码会在内存中发生,因为SQLite不了解NSCoding或您的类。

您的原始分配有效,因为Core Data会将transformableAttr的值转换为内存中的Data,然后将Data的字节保存到持久性存储中。在批量更新中,对象没有加载到内存中,因此转换无法运行,因此更新不会像您期望的那样工作。

令人失望的是Core Data并没有让这一点更加清晰。查看Xcode控制台,看看它是否会对此发出警告。如果它没有,请向Apple提交一个错误,因为虽然我不希望这种情况发生,但它也无法以静默方式失败。

如果要使用批量更新,则必须在运行更新之前在代码中转换值。我不能100%确定这是如何运作的,但如果您的价值符合NSCoding,那么您将从

开始
let transformedData: Data = NSKeyedArchiver.archivedData(withRootObject:transformableAttr)

你所做的就是我不确定的地方。您可以使用transformedData作为新值。或者您可能必须访问其字节并以某种方式使用它们 - 可能使用withUnsafeBytes(_:)。您可能遇到麻烦,因为transformableAttr不是Data,因此可能会变得混乱。似乎批量更新并非设计为可以与变换一起使用。