Crash while trying refetch listMonitor after data stack is recreated. #203

Closed
opened 2025-12-29 15:26:34 +01:00 by adam · 4 comments
Owner

Originally created by @sidlatau on GitHub (Mar 2, 2018).

Hi, I am recreating database by physically deleting/moving DB files after each login to app.
After file is moved I recreate data stack by calling:

let dataStack = DataStack(
            xcodeModelName: "..."
        )
try dataStack.addStorageAndWait(
                SQLiteStore(
                    fileURL: sqliteFileURL,
                    localStorageOptions: .allowSynchronousLightweightMigration
                )
            )

But if ListMonitor was created on old data stack I get crash there:

internal func applyToFetchRequest<ResultType>(...) {
fetchRequest.entity = context.parentStack!.entityDescription(for: EntityIdentifier(self.entityClass))!
...

parentStack there is nil.

This refetch is called from this observer:

self.observerForDidChangePersistentStore = NotificationObserver(...)
...
if previousStores != currentStores {
                        
                        self.refetch(self.applyFetchClauses)
                    }
...

I am using CoreStore v5.0.0.

Maybe there is a better way to recreate data stack or only one storage in that stack? I see there is method storage.cs_eraseStorageAndWait but it is specifically indicated not to use it directly.

Originally created by @sidlatau on GitHub (Mar 2, 2018). Hi, I am recreating database by physically deleting/moving DB files after each login to app. After file is moved I recreate data stack by calling: ``` let dataStack = DataStack( xcodeModelName: "..." ) try dataStack.addStorageAndWait( SQLiteStore( fileURL: sqliteFileURL, localStorageOptions: .allowSynchronousLightweightMigration ) ) ``` But if ListMonitor was created on old data stack I get crash there: ``` internal func applyToFetchRequest<ResultType>(...) { fetchRequest.entity = context.parentStack!.entityDescription(for: EntityIdentifier(self.entityClass))! ... ``` `parentStack` there is `nil`. This refetch is called from this observer: ``` self.observerForDidChangePersistentStore = NotificationObserver(...) ... if previousStores != currentStores { self.refetch(self.applyFetchClauses) } ... ``` I am using CoreStore v5.0.0. Maybe there is a better way to recreate data stack or only one storage in that stack? I see there is method `storage.cs_eraseStorageAndWait` but it is specifically indicated not to use it directly.
adam added the wontfix label 2025-12-29 15:26:34 +01:00
adam closed this issue 2025-12-29 15:26:35 +01:00
Author
Owner

@JohnEstropia commented on GitHub (Apr 14, 2018):

@sidlatau Have you solved your issue? I personally don't recommend moving SQLite files around, but if you really need to, just make sure that

  1. you also move any -wal files
  2. you recreate everything that was created from the old stack, including objects and ListMonitors
@JohnEstropia commented on GitHub (Apr 14, 2018): @sidlatau Have you solved your issue? I personally don't recommend moving SQLite files around, but if you really need to, just make sure that 1. you also move any `-wal` files 2. you recreate everything that was created from the old stack, including objects and `ListMonitor`s
Author
Owner

@sidlatau commented on GitHub (Apr 16, 2018):

No, I haven't solve the issue, I just stopped using ListMonitors . Despite that issue I am happily using CoreStore :) Thank you for your feedback.

@sidlatau commented on GitHub (Apr 16, 2018): No, I haven't solve the issue, I just stopped using `ListMonitor`s . Despite that issue I am happily using CoreStore :) Thank you for your feedback.
Author
Owner

@tosbaha commented on GitHub (May 5, 2018):

I had similar problems. I was using AppDelegate to initialize data stack and had ListMonitor in my main view. The thing is, in storyboard environments, viewDidLoad is called before AppDelegate and this messes up things. I learned my hard lesson that you shouldn't depend on AppDelegate. My approach is something like below

struct Storage {
    static let stack: DataStack = {
        let stack = DataStack(xcodeModelName: "Kargo",migrationChain: ["Kargo","KargoV2"])
        let sqliteFileURL = URL(....)
        try! stack.addStorageAndWait(
            SQLiteStore(fileURL: sqliteFileURL,  localStorageOptions: .allowSynchronousLightweightMigration)
        )
        return stack
   //If you prefer CoreStore functions, add to defaultStack

    }()

    static let kargos:ListMonitor<KargoCD> =  {
        return Storage.stack.monitorList(
            From<KargoCD>(),
            Where<KargoCD>(filter.predicate),
            OrderBy<KargoCD>((sort.descriptor))
        )
    }()
}

// The use it like below in your ViewController viewDidLoad

        Storage.kargos.addObserver(self)


@tosbaha commented on GitHub (May 5, 2018): I had similar problems. I was using AppDelegate to initialize data stack and had `ListMonitor` in my main view. The thing is, in storyboard environments, viewDidLoad is called before AppDelegate and this messes up things. I learned my hard lesson that you shouldn't depend on AppDelegate. My approach is something like below ```swift struct Storage { static let stack: DataStack = { let stack = DataStack(xcodeModelName: "Kargo",migrationChain: ["Kargo","KargoV2"]) let sqliteFileURL = URL(....) try! stack.addStorageAndWait( SQLiteStore(fileURL: sqliteFileURL, localStorageOptions: .allowSynchronousLightweightMigration) ) return stack //If you prefer CoreStore functions, add to defaultStack }() static let kargos:ListMonitor<KargoCD> = { return Storage.stack.monitorList( From<KargoCD>(), Where<KargoCD>(filter.predicate), OrderBy<KargoCD>((sort.descriptor)) ) }() } // The use it like below in your ViewController viewDidLoad Storage.kargos.addObserver(self) ```
Author
Owner

@JohnEstropia commented on GitHub (May 7, 2018):

@tosbaha Thanks for the feedback. Your pattern is the best practice as it is explicit about the initialization timing.

I am closing this issue as the OP seems to have gone to a different route to solve the issue.

@JohnEstropia commented on GitHub (May 7, 2018): @tosbaha Thanks for the feedback. Your pattern is the best practice as it is explicit about the initialization timing. I am closing this issue as the OP seems to have gone to a different route to solve the issue.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore#203