NSBatchUpdateRequest 不保存可转换属性
Posted
技术标签:
【中文标题】NSBatchUpdateRequest 不保存可转换属性【英文标题】:NSBatchUpdateRequest not saving Transformable attribute 【发布时间】:2018-01-22 19:23:31 【问题描述】:我有一个实体 (TestEntity
),它包含一个包含对象 (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
。
现在这只发生在“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】:文档似乎没有提到这种特殊情况,但我对它不起作用并不感到惊讶。 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
,所以它可能会变得混乱。批量更新似乎不适用于可转换对象。
【讨论】:
感谢您的回答,它确实澄清了我的问题。我确实使用了适用于这两种情况的 NSData,但随着时间的推移,数据变得太大并影响了性能。不幸的是,日志中没有说明 NSBatchUpdateRequest 并将向苹果提交错误。 我能够使用 [NSKeyedArchiver archivedDataWithRootObject:@"MyTestString"] 作为 propertiesToEdit 字典中的值,它适用于我的可转换属性。我不能说 NSString 以外的值如何工作(没有测试)。以上是关于NSBatchUpdateRequest 不保存可转换属性的主要内容,如果未能解决你的问题,请参考以下文章
NSBatchUpdateRequest 在 Swift 中引发错误
使用 NSBatchUpdateRequest 将 Core Data 属性设置为 nil