I'm facing a strange behaviour with NSBatchInsertRequest
and I don't seems to understand what is causing my problem.
I have some piece of code that updates local data depending on some remote data changes.
The model that is being updated contains a boolean shared
indicating if the item is shared or not. Updating this model seems to work correctly when the boolean goes from false
to true
but when trying to update the data with the reverse action the new local data doesn't seem to be persisted and I end up having the shared
variable always returning true
even is the content of the NSBatchInsertRequest
has it set as false
.
Following are the different parts of my logic and my managed object description.
Helper functions
func newTaskContext(type: TaskContextType,
transactionAuthor: String = #function) -> NSManagedObjectContext {
let taskContext = container.newBackgroundContext()
taskContext.name = type.rawValue
taskContext.transactionAuthor = transactionAuthor
taskContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
taskContext.undoManager = nil
return taskContext
}
func newBatchInsertRequest<T>(entity: NSEntityDescription,
sourceItems: [T],
hydrateBlock: @escaping (NSManagedObject, T) -> Void)
-> NSBatchInsertRequest {
var index = 0
let request = NSBatchInsertRequest(entity: entity,
managedObjectHandler: { object in
guard index < sourceItems.count else { return true }
let item = sourceItems[index]
hydrateBlock(object, item)
index += 1
return false
})
return request
}
extension ShareEntity {
func hydrate(from symmetricallyEncryptedShare: SymmetricallyEncryptedShare, userId: String) {
let share = symmetricallyEncryptedShare.share
content = share.content
contentFormatVersion = share.contentFormatVersion ?? -1
contentKeyRotation = share.contentKeyRotation ?? -1
createTime = share.createTime
expireTime = share.expireTime ?? -1
owner = share.owner
permission = share.permission
primary = share.primary
shareID = share.shareID
symmetricallyEncryptedContent = symmetricallyEncryptedShare.encryptedContent
targetID = share.targetID
targetType = share.targetType
vaultID = share.vaultID
addressID = share.addressID
userID = userId
shareRoleID = share.shareRoleID
targetMembers = share.targetMembers
shared = share.shared
}
}
func execute(batchInsertRequest request: NSBatchInsertRequest,
context: NSManagedObjectContext) async throws {
try await context.perform {
guard context.hasPersistentStore else { return }
let fetchResult = try context.execute(request)
if let result = fetchResult as? NSBatchInsertResult,
let success = result.result as? Bool, success {
return
} else {
throw error
}
}
}
Main local data updating entry point
func upsertShares(_ shares: [SymmetricallyEncryptedShare], userId: String) async throws {
let taskContext = newTaskContext(type: .insert)
let batchInsertRequest =
newBatchInsertRequest(entity: ShareEntity.entity(context: taskContext),
sourceItems: shares) { managedObject, share in
(managedObject as? ShareEntity)?.hydrate(from: share, userId: userId)
}
try await execute(batchInsertRequest: batchInsertRequest, context: taskContext)
}
I don't understand why the update of ShareEntity
work one way but cannot be updated back to containing the variable shared
as false.
Any tips or advice would be welcome on this issue.