Save current user's portfolio to Core Data with MVVM | SwiftUI Crypto App #15
private func fetchPortfolio() {
let request = NSFetchRequest<PortfolioEntity>(entityName: entityName)
do {
savedEntities = try container.viewContext.fetch(request)
} catch {
print("Error fetching Portfolio Entities: \(error.localizedDescription)")
}
}
private func save() {
do {
try container.viewContext.save()
} catch {
print("Error saving Coredata: \(error.localizedDescription)")
}
}
private func applyChange() {
save()
fetchPortfolio()
}
private func add(coin: CoinModel, amount: Double) {
let entitiy = PortfolioEntity(context: container.viewContext)
entitiy.coinID = coin.id
entitiy.amount = amount
applyChange()
}
private func update(entity: PortfolioEntity, amount: Double) {
entity.amount = amount
applyChange()
}
private func delete(entity: PortfolioEntity) {
container.viewContext.delete(entity)
applyChange()
}
func updatePortfolio(coin: CoinModel, amount: Double) {
if let entity = savedEntities.first(where: {$0.coinID == coin.id }) {
if amount > 0 {
update(entity: entity, amount: amount)
} else {
delete(entity: entity)
}
} else {
if amount > 0 {
add(coin: coin, amount: amount)
}
}
}
amount
값에 따라 해당 코인 데이터의 추가 및 삭제 여부 판단$allCoins
.combineLatest(portfolioDataService.$savedEntities)
.map { (coinModels, portfolioEntities) -> [CoinModel] in
coinModels
.compactMap { coin -> CoinModel? in
guard let entity = portfolioEntities.first(where: { $0.coinID == coin.id }) else { return nil }
return coin.updateHoldings(amount: entity.amount)
}
}
.sink { [weak self] coinModels in
self?.portfolioCoins = coinModels
}
.store(in: &cancellables)
combineLatest
compactMap
를 통해 엔티티 정보를 통해 새롭게 코인 업데이트import Foundation
import CoreData
class PortfolioDataService {
private let container: NSPersistentContainer
private let containerName: String = "PortfolioContainer"
private let entityName: String = "PortfolioEntity"
@Published var savedEntities: [PortfolioEntity] = []
init() {
container = NSPersistentContainer(name: containerName)
container.loadPersistentStores { [weak self] _, error in
if let error = error {
print("Error loading Cor Data: \(error.localizedDescription)")
}
self?.fetchPortfolio()
}
}
// MARK: PUBLIC
func updatePortfolio(coin: CoinModel, amount: Double) {
print("Coin: \(coin.id)")
print("Coin Amount: \(coin.currentHoldings ?? 0.0)")
print("Coin Name: \(coin.name)")
if let entity = savedEntities.first(where: {$0.coinID == coin.id }) {
if amount > 0 {
update(entity: entity, amount: amount)
} else {
delete(entity: entity)
}
} else {
add(coin: coin, amount: amount)
}
}
// MARK: PRIVATE
private func fetchPortfolio() {
let request = NSFetchRequest<PortfolioEntity>(entityName: entityName)
do {
savedEntities = try container.viewContext.fetch(request)
} catch {
print("Error fetching Portfolio Entities: \(error.localizedDescription)")
}
}
private func add(coin: CoinModel, amount: Double) {
let entitiy = PortfolioEntity(context: container.viewContext)
entitiy.coinID = coin.id
entitiy.amount = amount
applyChange()
}
private func save() {
do {
try container.viewContext.save()
} catch {
print("Error saving Coredata: \(error.localizedDescription)")
}
}
private func applyChange() {
save()
fetchPortfolio()
}
private func update(entity: PortfolioEntity, amount: Double) {
entity.amount = amount
applyChange()
}
private func delete(entity: PortfolioEntity) {
container.viewContext.delete(entity)
applyChange()
}
}
init
단에서 코어 데이터 로드 및 데이터 패치updatePortfolio
로 publicprivate func saveButtonPressed() {
guard
let coin = selectedCoin,
let amount = Double(quantityText) else { return }
// save to portfolio
viewModel.updatePortfolio(coin: coin, amount: amount)
...
}
amount
및 코인 정보를 확인updatePortfolio
를 통해 포트폴리오 CRUDprivate func updateSelectedCoin(coin: CoinModel) {
if selectedCoin?.id == coin.id {
selectedCoin = nil
} else {
selectedCoin = coin
if
let portfolioCoin = viewModel.portfolioCoins.first(where: { $0.id == coin.id }),
let amount = portfolioCoin.currentHoldings {
quantityText = "\(amount)"
} else {
quantityText = ""
}
}
}
amount
를 표시