From b4e712f6b8566896d4714f672eb94c1404ef6846 Mon Sep 17 00:00:00 2001 From: dankito Date: Tue, 1 Sep 2020 14:22:04 +0200 Subject: [PATCH] Fixed that caching Core Data entities in Dictionaries didn't really work. Setting now Core Data Ids on BankingUi model classes and retrieving Core Data entities by that ID --- .../banking/ui/model/tan/TanProcedure.kt | 4 +++ .../CoreDataBankingPersistence.swift | 19 +++++++++++ .../BankingiOSApp/persistence/Mapper.swift | 34 ++++--------------- .../BankingiOSApp/ui/SwiftExtensions.swift | 34 +++++++++++++++++++ 4 files changed, 63 insertions(+), 28 deletions(-) diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanProcedure.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanProcedure.kt index 88bc2048..bcd27265 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanProcedure.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanProcedure.kt @@ -1,6 +1,7 @@ package net.dankito.banking.ui.model.tan import net.dankito.banking.ui.model.Displayable +import net.dankito.utils.multiplatform.UUID open class TanProcedure( @@ -18,6 +19,9 @@ open class TanProcedure( val isNumericTan: Boolean = allowedTanFormat == AllowedTanFormat.Numeric + open var technicalId: String = UUID.random() + + override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is TanProcedure) return false diff --git a/ui/BankingiOSApp/BankingiOSApp/persistence/CoreDataBankingPersistence.swift b/ui/BankingiOSApp/BankingiOSApp/persistence/CoreDataBankingPersistence.swift index 3471843a..e4d45fd5 100644 --- a/ui/BankingiOSApp/BankingiOSApp/persistence/CoreDataBankingPersistence.swift +++ b/ui/BankingiOSApp/BankingiOSApp/persistence/CoreDataBankingPersistence.swift @@ -26,11 +26,30 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher { context.insert(mapped) try context.save() + + setIds(customer, mapped) } catch { NSLog("Could not save Customer \(customer): \(error)") } } + private func setIds(_ customer: Customer, _ mappedCustomer: PersistedCustomer) { + customer.technicalId = mappedCustomer.objectIDAsString + + for account in customer.accounts { + if let mappedAccount = mappedCustomer.accounts?.first { ($0 as! PersistedBankAccount).identifier == account.identifier} as? PersistedBankAccount { + account.technicalId = mappedAccount.objectIDAsString + } + } + + for tanProcedure in customer.supportedTanProcedures { + if let mappedTanProcedure = mappedCustomer.supportedTanProcedures?.first { ($0 as! PersistedTanProcedure).bankInternalProcedureCode == tanProcedure.bankInternalProcedureCode } as? PersistedTanProcedure { + tanProcedure.technicalId = mappedTanProcedure.objectIDAsString + } + } + } + + func readPersistedAccounts_() -> [Customer] { var customers: [PersistedCustomer] = [] diff --git a/ui/BankingiOSApp/BankingiOSApp/persistence/Mapper.swift b/ui/BankingiOSApp/BankingiOSApp/persistence/Mapper.swift index 3d6ab8c9..4d5205fc 100644 --- a/ui/BankingiOSApp/BankingiOSApp/persistence/Mapper.swift +++ b/ui/BankingiOSApp/BankingiOSApp/persistence/Mapper.swift @@ -4,16 +4,6 @@ import BankingUiSwift class Mapper { - - /* Cache mapped object to not save them twice */ - private var mappedBanks = [Customer:PersistedCustomer]() - - private var mappedAccounts = [BankAccount:PersistedBankAccount]() - - private var mappedTransactions = [AccountTransaction:PersistedAccountTransaction]() - - private var mappedTanProcedures = [TanProcedure:PersistedTanProcedure]() - func map(_ customer: PersistedCustomer) -> Customer { let mapped = Customer(bankCode: map(customer.bankCode), customerId: map(customer.customerId), password: map(customer.password), finTsServerAddress: map(customer.finTsServerAddress), bankName: map(customer.bankName), bic: map(customer.bic), customerName: map(customer.customerName), userId: map(customer.userId), iconUrl: customer.iconUrl, accounts: []) @@ -28,13 +18,11 @@ class Mapper { mapped.technicalId = customer.objectIDAsString - mappedBanks[mapped] = customer - return mapped } func map(_ customer: Customer, _ context: NSManagedObjectContext) -> PersistedCustomer { - let mapped = mappedBanks[customer] ?? PersistedCustomer(context: context) + let mapped = context.objectByID(customer.technicalId) ?? PersistedCustomer(context: context) mapped.bankCode = customer.bankCode mapped.customerId = customer.customerId @@ -51,8 +39,6 @@ class Mapper { mapped.accounts = NSOrderedSet(array: map(mapped, customer.accounts, context)) - mappedBanks[customer] = mapped - mapped.supportedTanProcedures = NSOrderedSet(array: map(customer.supportedTanProcedures, context)) mapped.selectedTanProcedureCode = customer.selectedTanProcedure?.bankInternalProcedureCode @@ -76,8 +62,6 @@ class Mapper { mapped.technicalId = account.objectIDAsString - mappedAccounts[mapped] = account - return mapped } @@ -86,7 +70,7 @@ class Mapper { } func map(_ customer: PersistedCustomer, _ account: BankAccount, _ context: NSManagedObjectContext) -> PersistedBankAccount { - let mapped = mappedAccounts[account] ?? PersistedBankAccount(context: context) + let mapped = context.objectByID(account.technicalId) ?? PersistedBankAccount(context: context) mapped.customer = customer mapped.identifier = account.identifier @@ -112,8 +96,6 @@ class Mapper { mapped.transactions = NSSet(array: map(mapped, account.bookedTransactions, context)) - mappedAccounts[account] = mapped - return mapped } @@ -157,7 +139,7 @@ class Mapper { func map(_ account: BankAccount, _ transaction: PersistedAccountTransaction) -> AccountTransaction { let mapped = AccountTransaction(bankAccount: account, amount: map(transaction.amount), currency: map(transaction.currency), unparsedUsage: map(transaction.unparsedUsage), bookingDate: map(transaction.bookingDate), otherPartyName: transaction.otherPartyName, otherPartyBankCode: transaction.otherPartyBankCode, otherPartyAccountId: transaction.otherPartyAccountId, bookingText: transaction.bookingText, valueDate: map(transaction.valueDate), statementNumber: Int32(transaction.statementNumber), sequenceNumber: map(transaction.sequenceNumber), openingBalance: map(transaction.openingBalance), closingBalance: map(transaction.closingBalance), endToEndReference: transaction.endToEndReference, customerReference: transaction.customerReference, mandateReference: transaction.mandateReference, creditorIdentifier: transaction.creditorIdentifier, originatorsIdentificationCode: transaction.originatorsIdentificationCode, compensationAmount: transaction.compensationAmount, originalAmount: transaction.originalAmount, sepaUsage: transaction.sepaUsage, deviantOriginator: transaction.deviantOriginator, deviantRecipient: transaction.deviantRecipient, usageWithNoSpecialType: transaction.usageWithNoSpecialType, primaNotaNumber: transaction.primaNotaNumber, textKeySupplement: transaction.textKeySupplement, currencyType: transaction.currencyType, bookingKey: map(transaction.bookingKey), referenceForTheAccountOwner: map(transaction.referenceForTheAccountOwner), referenceOfTheAccountServicingInstitution: transaction.referenceOfTheAccountServicingInstitution, supplementaryDetails: transaction.supplementaryDetails, transactionReferenceNumber: map(transaction.transactionReferenceNumber), relatedReferenceNumber: transaction.relatedReferenceNumber) - mappedTransactions[mapped] = transaction + mapped.technicalId = transaction.objectIDAsString return mapped } @@ -168,7 +150,7 @@ class Mapper { } func map(_ account: PersistedBankAccount, _ transaction: AccountTransaction, _ context: NSManagedObjectContext) -> PersistedAccountTransaction { - let mapped = mappedTransactions[transaction] ?? PersistedAccountTransaction(context: context) + let mapped = context.objectByID(transaction.technicalId) ?? PersistedAccountTransaction(context: context) mapped.account = account @@ -210,8 +192,6 @@ class Mapper { mapped.transactionReferenceNumber = transaction.transactionReferenceNumber mapped.relatedReferenceNumber = transaction.relatedReferenceNumber - mappedTransactions[transaction] = mapped - return mapped } @@ -229,7 +209,7 @@ class Mapper { allowedTanFormat: tanProcedure.allowedTanFormat == "numeric" ? .numeric : .alphanumeric ) - mappedTanProcedures[mapped] = tanProcedure + mapped.technicalId = tanProcedure.objectIDAsString return mapped } @@ -239,7 +219,7 @@ class Mapper { } func map(_ tanProcedure: TanProcedure, _ context: NSManagedObjectContext) -> PersistedTanProcedure { - let mapped = mappedTanProcedures[tanProcedure] ?? PersistedTanProcedure(context: context) + let mapped = context.objectByID(tanProcedure.technicalId) ?? PersistedTanProcedure(context: context) mapped.displayName = tanProcedure.displayName mapped.type = tanProcedure.type.name @@ -248,8 +228,6 @@ class Mapper { mapped.maxTanInputLength = map(tanProcedure.maxTanInputLength) ?? -1 mapped.allowedTanFormat = tanProcedure.allowedTanFormat.name - mappedTanProcedures[tanProcedure] = mapped - return mapped } diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/SwiftExtensions.swift b/ui/BankingiOSApp/BankingiOSApp/ui/SwiftExtensions.swift index 7cb114a5..d82e1f26 100644 --- a/ui/BankingiOSApp/BankingiOSApp/ui/SwiftExtensions.swift +++ b/ui/BankingiOSApp/BankingiOSApp/ui/SwiftExtensions.swift @@ -1,4 +1,5 @@ import SwiftUI +import CoreData extension String { @@ -39,6 +40,11 @@ extension String { return String(self[startIndex...endIndex]) } + + var isCoreDataId: Bool { + return self.starts(with: "x-coredata://") + } + } extension Optional where Wrapped == String { @@ -171,3 +177,31 @@ extension URL { } } + + +extension NSManagedObject { + + var objectIDAsString: String { + return self.objectID.uriRepresentation().absoluteString + } + +} + +extension NSManagedObjectContext { + + func objectByID(_ objectID: String) -> T? { + if objectID.isCoreDataId { + if let url = URL(string: objectID) { + if let managedObjectId = self.persistentStoreCoordinator?.managedObjectID(forURIRepresentation: url) { + let object = try? self.existingObject(with: managedObjectId) as? T + if object?.isFault == false { + return object + } + } + } + } + + return nil + } + +}