Utilize NSFetchedResultsController to update the deck when answers are recorded.
This commit is contained in:
parent
7b3cbd9038
commit
a1efa0f6c6
|
@ -34,7 +34,7 @@
|
||||||
F378AA0E23D4CC6400296A76 /* DraggableCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA0D23D4CC6400296A76 /* DraggableCardView.swift */; };
|
F378AA0E23D4CC6400296A76 /* DraggableCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA0D23D4CC6400296A76 /* DraggableCardView.swift */; };
|
||||||
F378AA1023D5BAD500296A76 /* CardDeckView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA0F23D5BAD500296A76 /* CardDeckView.swift */; };
|
F378AA1023D5BAD500296A76 /* CardDeckView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA0F23D5BAD500296A76 /* CardDeckView.swift */; };
|
||||||
F378AA1323D63AA700296A76 /* NumberFormatters.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA1223D63AA700296A76 /* NumberFormatters.swift */; };
|
F378AA1323D63AA700296A76 /* NumberFormatters.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA1223D63AA700296A76 /* NumberFormatters.swift */; };
|
||||||
F378AA1523D7156200296A76 /* Card+Outcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA1423D7156100296A76 /* Card+Outcome.swift */; };
|
F378AA1523D7156200296A76 /* Card+AnswerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA1423D7156100296A76 /* Card+AnswerState.swift */; };
|
||||||
F378AA1723D733EF00296A76 /* EditDeckView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA1623D733EE00296A76 /* EditDeckView.swift */; };
|
F378AA1723D733EF00296A76 /* EditDeckView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA1623D733EE00296A76 /* EditDeckView.swift */; };
|
||||||
F378AA1923D7359B00296A76 /* EditDeckView+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA1823D7359B00296A76 /* EditDeckView+ViewModel.swift */; };
|
F378AA1923D7359B00296A76 /* EditDeckView+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA1823D7359B00296A76 /* EditDeckView+ViewModel.swift */; };
|
||||||
F378AA1B23D7A06600296A76 /* CountdownTimerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA1A23D7A06500296A76 /* CountdownTimerView.swift */; };
|
F378AA1B23D7A06600296A76 /* CountdownTimerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA1A23D7A06500296A76 /* CountdownTimerView.swift */; };
|
||||||
|
@ -43,6 +43,7 @@
|
||||||
F378AA2323D7B8D900296A76 /* CardDeck+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA2123D7B8D900296A76 /* CardDeck+CoreDataProperties.swift */; };
|
F378AA2323D7B8D900296A76 /* CardDeck+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA2123D7B8D900296A76 /* CardDeck+CoreDataProperties.swift */; };
|
||||||
F378AA2523D7B91E00296A76 /* CardDeck+Computeds.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA2423D7B91E00296A76 /* CardDeck+Computeds.swift */; };
|
F378AA2523D7B91E00296A76 /* CardDeck+Computeds.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA2423D7B91E00296A76 /* CardDeck+Computeds.swift */; };
|
||||||
F378AA3023D8909C00296A76 /* KeyboardAvoider in Frameworks */ = {isa = PBXBuildFile; productRef = F378AA2F23D8909C00296A76 /* KeyboardAvoider */; };
|
F378AA3023D8909C00296A76 /* KeyboardAvoider in Frameworks */ = {isa = PBXBuildFile; productRef = F378AA2F23D8909C00296A76 /* KeyboardAvoider */; };
|
||||||
|
F378AA3223D8A6EA00296A76 /* Card+FetchHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA3123D8A6EA00296A76 /* Card+FetchHelpers.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
@ -72,7 +73,7 @@
|
||||||
F378AA0D23D4CC6400296A76 /* DraggableCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableCardView.swift; sourceTree = "<group>"; };
|
F378AA0D23D4CC6400296A76 /* DraggableCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableCardView.swift; sourceTree = "<group>"; };
|
||||||
F378AA0F23D5BAD500296A76 /* CardDeckView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardDeckView.swift; sourceTree = "<group>"; };
|
F378AA0F23D5BAD500296A76 /* CardDeckView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardDeckView.swift; sourceTree = "<group>"; };
|
||||||
F378AA1223D63AA700296A76 /* NumberFormatters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberFormatters.swift; sourceTree = "<group>"; };
|
F378AA1223D63AA700296A76 /* NumberFormatters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberFormatters.swift; sourceTree = "<group>"; };
|
||||||
F378AA1423D7156100296A76 /* Card+Outcome.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Card+Outcome.swift"; sourceTree = "<group>"; };
|
F378AA1423D7156100296A76 /* Card+AnswerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Card+AnswerState.swift"; sourceTree = "<group>"; };
|
||||||
F378AA1623D733EE00296A76 /* EditDeckView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditDeckView.swift; sourceTree = "<group>"; };
|
F378AA1623D733EE00296A76 /* EditDeckView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditDeckView.swift; sourceTree = "<group>"; };
|
||||||
F378AA1823D7359B00296A76 /* EditDeckView+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EditDeckView+ViewModel.swift"; sourceTree = "<group>"; };
|
F378AA1823D7359B00296A76 /* EditDeckView+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EditDeckView+ViewModel.swift"; sourceTree = "<group>"; };
|
||||||
F378AA1A23D7A06500296A76 /* CountdownTimerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountdownTimerView.swift; sourceTree = "<group>"; };
|
F378AA1A23D7A06500296A76 /* CountdownTimerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountdownTimerView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -80,6 +81,7 @@
|
||||||
F378AA2023D7B8D900296A76 /* CardDeck+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CardDeck+CoreDataClass.swift"; sourceTree = "<group>"; };
|
F378AA2023D7B8D900296A76 /* CardDeck+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CardDeck+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||||
F378AA2123D7B8D900296A76 /* CardDeck+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CardDeck+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
F378AA2123D7B8D900296A76 /* CardDeck+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CardDeck+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
||||||
F378AA2423D7B91E00296A76 /* CardDeck+Computeds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CardDeck+Computeds.swift"; sourceTree = "<group>"; };
|
F378AA2423D7B91E00296A76 /* CardDeck+Computeds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CardDeck+Computeds.swift"; sourceTree = "<group>"; };
|
||||||
|
F378AA3123D8A6EA00296A76 /* Card+FetchHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Card+FetchHelpers.swift"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -216,7 +218,8 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
F378A9F423D44E3800296A76 /* Card+CoreDataClass.swift */,
|
F378A9F423D44E3800296A76 /* Card+CoreDataClass.swift */,
|
||||||
F378AA1423D7156100296A76 /* Card+Outcome.swift */,
|
F378AA3123D8A6EA00296A76 /* Card+FetchHelpers.swift */,
|
||||||
|
F378AA1423D7156100296A76 /* Card+AnswerState.swift */,
|
||||||
F378A9F523D44E3900296A76 /* Card+CoreDataProperties.swift */,
|
F378A9F523D44E3900296A76 /* Card+CoreDataProperties.swift */,
|
||||||
);
|
);
|
||||||
path = Card;
|
path = Card;
|
||||||
|
@ -382,6 +385,7 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
F378AA0423D48D6D00296A76 /* CardDeckContainerView+ViewModel.swift in Sources */,
|
F378AA0423D48D6D00296A76 /* CardDeckContainerView+ViewModel.swift in Sources */,
|
||||||
|
F378AA3223D8A6EA00296A76 /* Card+FetchHelpers.swift in Sources */,
|
||||||
F378AA1E23D7A0B900296A76 /* CountdownTimerView+ViewModel.swift in Sources */,
|
F378AA1E23D7A0B900296A76 /* CountdownTimerView+ViewModel.swift in Sources */,
|
||||||
F378A9F623D44E3900296A76 /* Card+CoreDataClass.swift in Sources */,
|
F378A9F623D44E3900296A76 /* Card+CoreDataClass.swift in Sources */,
|
||||||
F378AA0C23D4A5D300296A76 /* View+Stacked.swift in Sources */,
|
F378AA0C23D4A5D300296A76 /* View+Stacked.swift in Sources */,
|
||||||
|
@ -400,7 +404,7 @@
|
||||||
F378A9E623D43A6900296A76 /* CoreDataManager+Utils.swift in Sources */,
|
F378A9E623D43A6900296A76 /* CoreDataManager+Utils.swift in Sources */,
|
||||||
F378AA1023D5BAD500296A76 /* CardDeckView.swift in Sources */,
|
F378AA1023D5BAD500296A76 /* CardDeckView.swift in Sources */,
|
||||||
F378AA1723D733EF00296A76 /* EditDeckView.swift in Sources */,
|
F378AA1723D733EF00296A76 /* EditDeckView.swift in Sources */,
|
||||||
F378AA1523D7156200296A76 /* Card+Outcome.swift in Sources */,
|
F378AA1523D7156200296A76 /* Card+AnswerState.swift in Sources */,
|
||||||
F378AA1923D7359B00296A76 /* EditDeckView+ViewModel.swift in Sources */,
|
F378AA1923D7359B00296A76 /* EditDeckView+ViewModel.swift in Sources */,
|
||||||
F378A9F323D43CAA00296A76 /* PreviewData+Cards.swift in Sources */,
|
F378A9F323D43CAA00296A76 /* PreviewData+Cards.swift in Sources */,
|
||||||
F378AA0223D48CB900296A76 /* CardDeckContainerView.swift in Sources */,
|
F378AA0223D48CB900296A76 /* CardDeckContainerView.swift in Sources */,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import CoreData
|
||||||
|
|
||||||
@objc(CardDeck)
|
@objc(CardDeck)
|
||||||
public class CardDeck: NSManagedObject {
|
public class CardDeck: NSManagedObject {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CardDeck: Identifiable {}
|
extension CardDeck: Identifiable {}
|
||||||
|
|
|
@ -21,6 +21,7 @@ extension CardDeck {
|
||||||
@NSManaged public var cards: NSSet?
|
@NSManaged public var cards: NSSet?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Generated accessors for cards
|
// MARK: Generated accessors for cards
|
||||||
extension CardDeck {
|
extension CardDeck {
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,6 @@ import CoreData
|
||||||
|
|
||||||
|
|
||||||
extension Card {
|
extension Card {
|
||||||
|
|
||||||
@nonobjc public class func fetchRequest() -> NSFetchRequest<Card> {
|
|
||||||
return NSFetchRequest<Card>(entityName: "Card")
|
|
||||||
}
|
|
||||||
|
|
||||||
@NSManaged public var prompt: String?
|
@NSManaged public var prompt: String?
|
||||||
@NSManaged public var answer: String?
|
@NSManaged public var answer: String?
|
||||||
@NSManaged public var decks: NSSet?
|
@NSManaged public var decks: NSSet?
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
//
|
||||||
|
// Card+FetchHelpers.swift
|
||||||
|
// Flashzilla
|
||||||
|
//
|
||||||
|
// Created by CypherPoet on 1/22/20.
|
||||||
|
// ✌️
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import CoreData
|
||||||
|
import CypherPoetCoreDataKit_PredicateUtils
|
||||||
|
|
||||||
|
|
||||||
|
extension Card {
|
||||||
|
|
||||||
|
@nonobjc public class func fetchRequest() -> NSFetchRequest<Card> {
|
||||||
|
return NSFetchRequest<Card>(entityName: "Card")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public enum SortDescriptors {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public enum Predicate {
|
||||||
|
|
||||||
|
public static func cards(in cardDeck: CardDeck) -> NSPredicate {
|
||||||
|
let keyword = NSComparisonPredicate.keyword(for: .contains)
|
||||||
|
|
||||||
|
let predicate = NSPredicate(
|
||||||
|
format: "%K \(keyword) %@",
|
||||||
|
#keyPath(Card.decks),
|
||||||
|
cardDeck.objectID
|
||||||
|
)
|
||||||
|
|
||||||
|
return predicate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@nonobjc public class func fetchRequest(
|
||||||
|
forCardsIn cardDeck: CardDeck
|
||||||
|
) -> NSFetchRequest<Card> {
|
||||||
|
let fetchRequest: NSFetchRequest<Card> = Self.fetchRequest()
|
||||||
|
|
||||||
|
fetchRequest.sortDescriptors = []
|
||||||
|
fetchRequest.predicate = Self.Predicate.cards(in: cardDeck)
|
||||||
|
|
||||||
|
return fetchRequest
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,11 @@ public protocol FetchedResultsControlling: NSObject {
|
||||||
var fetchRequest: NSFetchRequest<FetchedResult> { get }
|
var fetchRequest: NSFetchRequest<FetchedResult> { get }
|
||||||
var fetchedResultsController: NSFetchedResultsController<FetchedResult> { get }
|
var fetchedResultsController: NSFetchedResultsController<FetchedResult> { get }
|
||||||
|
|
||||||
func makeFetchedResultsController() -> FetchedResultsController
|
func makeFetchedResultsController(
|
||||||
|
sectionNameKeyPath: String?,
|
||||||
|
cacheName: String?
|
||||||
|
) -> FetchedResultsController
|
||||||
|
|
||||||
func extractResults(from fetchedResultsController: FetchedResultsController) -> [FetchedResult]
|
func extractResults(from fetchedResultsController: FetchedResultsController) -> [FetchedResult]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,12 +30,15 @@ extension FetchedResultsControlling {
|
||||||
public typealias FetchRequest = NSFetchRequest<FetchedResult>
|
public typealias FetchRequest = NSFetchRequest<FetchedResult>
|
||||||
|
|
||||||
|
|
||||||
public func makeFetchedResultsController() -> FetchedResultsController {
|
public func makeFetchedResultsController(
|
||||||
|
sectionNameKeyPath: String? = nil,
|
||||||
|
cacheName: String? = nil
|
||||||
|
) -> FetchedResultsController {
|
||||||
.init(
|
.init(
|
||||||
fetchRequest: fetchRequest,
|
fetchRequest: fetchRequest,
|
||||||
managedObjectContext: CurrentApp.coreDataManager.mainContext,
|
managedObjectContext: CurrentApp.coreDataManager.mainContext,
|
||||||
sectionNameKeyPath: nil,
|
sectionNameKeyPath: sectionNameKeyPath,
|
||||||
cacheName: nil
|
cacheName: cacheName
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,20 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Combine
|
import Combine
|
||||||
import CoreData
|
import CoreData
|
||||||
|
import CypherPoetCoreDataKit
|
||||||
|
|
||||||
|
|
||||||
extension CardDeckContainerView {
|
extension CardDeckContainerView {
|
||||||
|
|
||||||
final class ViewModel: ObservableObject {
|
final class ViewModel: NSObject, ObservableObject, FetchedResultsControlling {
|
||||||
|
typealias FetchedResult = Card
|
||||||
|
|
||||||
|
lazy var fetchRequest: NSFetchRequest<Card> = Card.fetchRequest(forCardsIn: cardDeck)
|
||||||
|
internal lazy var fetchedResultsController: FetchedResultsController = makeFetchedResultsController()
|
||||||
|
|
||||||
private var subscriptions = Set<AnyCancellable>()
|
private var subscriptions = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
|
||||||
@ObservedObject var cardDeck: CardDeck
|
@ObservedObject var cardDeck: CardDeck
|
||||||
|
|
||||||
var isTimerActive = false
|
var isTimerActive = false
|
||||||
|
@ -25,6 +32,7 @@ extension CardDeckContainerView {
|
||||||
|
|
||||||
// MARK: - Published Outputs
|
// MARK: - Published Outputs
|
||||||
@Published var cards: [Card] = []
|
@Published var cards: [Card] = []
|
||||||
|
@Published var visibleCards: [Card] = []
|
||||||
@Published var timeRemaining: TimeInterval
|
@Published var timeRemaining: TimeInterval
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,7 +45,11 @@ extension CardDeckContainerView {
|
||||||
self.roundDuration = roundDuration
|
self.roundDuration = roundDuration
|
||||||
self.timeRemaining = roundDuration
|
self.timeRemaining = roundDuration
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.fetchedResultsController.delegate = self
|
||||||
setupSubscribers()
|
setupSubscribers()
|
||||||
|
fetchCards()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,22 +77,17 @@ extension CardDeckContainerView.ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private var cardsPublisher: Publishers.Share<AnyPublisher<[Card], Never>> {
|
private var visibleCardsPublisher: AnyPublisher<[Card], Never> {
|
||||||
cardDeck.publisher(for: \.cards)
|
$cards
|
||||||
.map { _ in self.cardDeck.cardsArray }
|
.map { $0.filter { $0.answerState == .unanswered } }
|
||||||
|
// .print("visibleCardsPublisher")
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
.share()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Computeds
|
// MARK: - Computeds
|
||||||
extension CardDeckContainerView.ViewModel {
|
extension CardDeckContainerView.ViewModel {
|
||||||
|
|
||||||
var visibleCards: [Card] {
|
|
||||||
cards.filter { $0.answerState == .unanswered }
|
|
||||||
}
|
|
||||||
|
|
||||||
var isDeckEmpty: Bool { visibleCards.isEmpty }
|
var isDeckEmpty: Bool { visibleCards.isEmpty }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +96,12 @@ extension CardDeckContainerView.ViewModel {
|
||||||
// MARK: - Public Methods
|
// MARK: - Public Methods
|
||||||
extension CardDeckContainerView.ViewModel {
|
extension CardDeckContainerView.ViewModel {
|
||||||
|
|
||||||
|
func fetchCards() {
|
||||||
|
try? fetchedResultsController.performFetch()
|
||||||
|
cards = extractResults(from: fetchedResultsController)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func resetDeck() {
|
func resetDeck() {
|
||||||
cards.forEach { $0.answerState = .unanswered }
|
cards.forEach { $0.answerState = .unanswered }
|
||||||
|
|
||||||
|
@ -100,13 +113,14 @@ extension CardDeckContainerView.ViewModel {
|
||||||
isTimerActive = false
|
isTimerActive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func resumeRound() {
|
func resumeRound() {
|
||||||
isTimerActive = true
|
isTimerActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func record(_ answerState: Card.AnswerState, forCardAt index: Int) {
|
func record(_ answerState: Card.AnswerState, forCardAt index: Int) {
|
||||||
let card = cards[index]
|
let card = visibleCards[index]
|
||||||
|
|
||||||
guard let managedObjectContext = card.managedObjectContext else { fatalError() }
|
guard let managedObjectContext = card.managedObjectContext else { fatalError() }
|
||||||
|
|
||||||
|
@ -120,14 +134,13 @@ extension CardDeckContainerView.ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Private Helpers
|
// MARK: - Private Helpers
|
||||||
private extension CardDeckContainerView.ViewModel {
|
private extension CardDeckContainerView.ViewModel {
|
||||||
|
|
||||||
func setupSubscribers() {
|
func setupSubscribers() {
|
||||||
cardsPublisher
|
visibleCardsPublisher
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.assign(to: \.cards, on: self)
|
.assign(to: \.visibleCards, on: self)
|
||||||
.store(in: &subscriptions)
|
.store(in: &subscriptions)
|
||||||
|
|
||||||
timeRemainingPublisher
|
timeRemainingPublisher
|
||||||
|
@ -148,3 +161,15 @@ private extension CardDeckContainerView.ViewModel {
|
||||||
.store(in: &subscriptions)
|
.store(in: &subscriptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - NSFetchedResultsControllerDelegate
|
||||||
|
extension CardDeckContainerView.ViewModel: NSFetchedResultsControllerDelegate {
|
||||||
|
|
||||||
|
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
||||||
|
guard let controller = controller as? FetchedResultsController else { return }
|
||||||
|
|
||||||
|
print("controllerDidChangeContent")
|
||||||
|
cards = extractResults(from: controller)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue