fetchAll in ListPublisher observer doesnt get new data #417

Closed
opened 2025-12-29 15:31:18 +01:00 by adam · 14 comments
Owner

Originally created by @imrobbyrc on GitHub (Jul 27, 2023).

hi @JohnEstropia, i have some problem about corestore observer, can you help me?

this my method when fetch data from server and save it into database

try! Omni.dataStack.perform(synchronous: { transaction in
    try! Omni.deactivateAll(transaction: transaction,
                            objects: [Omni.Group.self, Omni.Variant.self, Omni.Product.self,
                                      Omni.Modifier.self, Omni.ModifierGroup.self])

    let groups = try! transaction.importUniqueObjects(Into<Omni.Group>(),
                                                      sourceArray: json["groups"].arrayValue)

    let products = try! transaction.importUniqueObjects(Into<Omni.Product>(),
                                             sourceArray: json["products"].arrayValue)

    let productMapping = products.reduce(into: [Int: Omni.Product]()) { (result, object) in
        result[object.id] = object
    }
    
    let groupMapping = groups.reduce(into: [Int: Omni.Group]()) { (result, object) in
        result[object.id] = object
    }

    _ = try! transaction.importUniqueObjects(
        Into<Omni.Variant>(),
        /**
         json["variants"] represents a list of variant objects obtained from the API.
         JSON Structure:
         [
             {
                "id": Int,
                "code": String,
                "name": String,
                ....
             },
         ]
         Example File: Tests/Resources/JSONFiles/inventories_with_no_modifiers.json
         */
        sourceArray: json["variants"].arrayValue, preProcess: { mapping in
            var variantMapping = [Int: JSON]()
            for (key, variantJSON) in mapping {
                guard var dict = variantJSON.dictionaryObject else { continue }
                if let productId = variantJSON["product_id"].int {
                    dict["product_object"] = productMapping[productId]
                }

                var groupObjects = Set<Omni.Group>()
                for groupId in variantJSON["groups"].arrayValue {
                    if let group = groupMapping[groupId.intValue] {
                        groupObjects.insert(group)
                    }
                }

                dict["group_objects"] = groupObjects
                variantMapping[key] = JSON(dict)
            }
            return variantMapping
        }
    )
})

and i add new observer in viewcontroller to notify when variant get updated, so i will fetch all groups data, but groups data is not get the latest one

variantPublisher.addObserver(self, notifyInitial: true) { [weak self] publisher in
    guard let self else { return }
    let groups = try! Omni.dataStack.fetchAll(
        From<Omni.Group>()
            .where(\.$isActive == true && \.$typeValue == GroupTypes.regular.rawValue)
            .orderBy(.ascending(\.$position))
    )
    self.categories = CategoryViewModel.forDisplay(groups: groups)
}
Originally created by @imrobbyrc on GitHub (Jul 27, 2023). hi @JohnEstropia, i have some problem about corestore observer, can you help me? this my method when fetch data from server and save it into database ```swift try! Omni.dataStack.perform(synchronous: { transaction in try! Omni.deactivateAll(transaction: transaction, objects: [Omni.Group.self, Omni.Variant.self, Omni.Product.self, Omni.Modifier.self, Omni.ModifierGroup.self]) let groups = try! transaction.importUniqueObjects(Into<Omni.Group>(), sourceArray: json["groups"].arrayValue) let products = try! transaction.importUniqueObjects(Into<Omni.Product>(), sourceArray: json["products"].arrayValue) let productMapping = products.reduce(into: [Int: Omni.Product]()) { (result, object) in result[object.id] = object } let groupMapping = groups.reduce(into: [Int: Omni.Group]()) { (result, object) in result[object.id] = object } _ = try! transaction.importUniqueObjects( Into<Omni.Variant>(), /** json["variants"] represents a list of variant objects obtained from the API. JSON Structure: [ { "id": Int, "code": String, "name": String, .... }, ] Example File: Tests/Resources/JSONFiles/inventories_with_no_modifiers.json */ sourceArray: json["variants"].arrayValue, preProcess: { mapping in var variantMapping = [Int: JSON]() for (key, variantJSON) in mapping { guard var dict = variantJSON.dictionaryObject else { continue } if let productId = variantJSON["product_id"].int { dict["product_object"] = productMapping[productId] } var groupObjects = Set<Omni.Group>() for groupId in variantJSON["groups"].arrayValue { if let group = groupMapping[groupId.intValue] { groupObjects.insert(group) } } dict["group_objects"] = groupObjects variantMapping[key] = JSON(dict) } return variantMapping } ) }) ``` and i add new observer in viewcontroller to notify when variant get updated, so i will fetch all groups data, but groups data is not get the latest one ```swift variantPublisher.addObserver(self, notifyInitial: true) { [weak self] publisher in guard let self else { return } let groups = try! Omni.dataStack.fetchAll( From<Omni.Group>() .where(\.$isActive == true && \.$typeValue == GroupTypes.regular.rawValue) .orderBy(.ascending(\.$position)) ) self.categories = CategoryViewModel.forDisplay(groups: groups) }
adam closed this issue 2025-12-29 15:31:18 +01:00
Author
Owner

@imrobbyrc commented on GitHub (Jul 27, 2023):

the result between fetchAll between fetchAll+ Where is different, all data should have isActive = true, but when i use where clause it only return 2 data, i have 3 active data with fetchAll only

Screen Shot 2023-07-27 at 22 48 54 Screen Shot 2023-07-27 at 22 49 08
@imrobbyrc commented on GitHub (Jul 27, 2023): the result between fetchAll between fetchAll+ Where is different, all data should have isActive = true, but when i use where clause it only return 2 data, i have 3 active data with fetchAll only <img width="496" alt="Screen Shot 2023-07-27 at 22 48 54" src="https://github.com/JohnEstropia/CoreStore/assets/25898417/5d9f5abf-1c92-4b79-8928-938efaf8cf2b"> <img width="501" alt="Screen Shot 2023-07-27 at 22 49 08" src="https://github.com/JohnEstropia/CoreStore/assets/25898417/1761cbc9-dae7-4663-b99a-8f3697eaecdb">
Author
Owner

@JohnEstropia commented on GitHub (Jul 28, 2023):

Why do you observe on variantPublisher but fetch different objects inside the observer handler? Your observer handler will run only on the changes affecting whatever predicate you assigned to variantPublisher, so you should be using the publisher.snapshot passed through the observer closure.

@JohnEstropia commented on GitHub (Jul 28, 2023): Why do you observe on `variantPublisher` but fetch different objects inside the observer handler? Your observer handler will run only on the changes affecting whatever predicate you assigned to `variantPublisher`, so you should be using the `publisher.snapshot` passed through the observer closure.
Author
Owner

@imrobbyrc commented on GitHub (Jul 28, 2023):

thanks for reply @JohnEstropia, i fetch different objects because variant have relation with groups, i need to know what groups that available for new data. i can use publisher.snapshot, but i need to iterrate all variants to get correct group

Screen Shot 2023-07-28 at 09 08 10
@imrobbyrc commented on GitHub (Jul 28, 2023): thanks for reply @JohnEstropia, i fetch different objects because variant have relation with groups, i need to know what groups that available for new data. i can use `publisher.snapshot`, but i need to iterrate all variants to get correct group <img width="539" alt="Screen Shot 2023-07-28 at 09 08 10" src="https://github.com/JohnEstropia/CoreStore/assets/25898417/918e258a-74f1-4307-82aa-1203ca5f6abc">
Author
Owner

@JohnEstropia commented on GitHub (Jul 28, 2023):

Your Variant publisher will not be notified even if any of their Groups are updated. You need to "ping" something in your Variant properties to update when their Group changes. Something like a lastGroupUpdateDate

@JohnEstropia commented on GitHub (Jul 28, 2023): Your `Variant` publisher will not be notified even if any of their `Group`s are updated. You need to "ping" something in your `Variant` properties to update when their `Group` changes. Something like a `lastGroupUpdateDate`
Author
Owner

@imrobbyrc commented on GitHub (Jul 28, 2023):

even i update groups in Variant ImportableUniqueObject protocol, my Variant publisher will not be notified?
Screen Shot 2023-07-28 at 09 36 25

@imrobbyrc commented on GitHub (Jul 28, 2023): even i update groups in `Variant` `ImportableUniqueObject` protocol, my `Variant` publisher will not be notified? <img width="755" alt="Screen Shot 2023-07-28 at 09 36 25" src="https://github.com/JohnEstropia/CoreStore/assets/25898417/7e98802a-5c5c-40e3-8912-57fb7a1fe5b5">
Author
Owner

@imrobbyrc commented on GitHub (Jul 28, 2023):

if i change my publisher closure to this, it will get a correct data instead of i use .where(\._isActive == true)

Screen Shot 2023-07-28 at 09 39 55
@imrobbyrc commented on GitHub (Jul 28, 2023): if i change my publisher closure to this, it will get a correct data instead of i use `.where(\._isActive == true)` <img width="572" alt="Screen Shot 2023-07-28 at 09 39 55" src="https://github.com/JohnEstropia/CoreStore/assets/25898417/2beb5977-ca74-40bc-ad91-5119390a536c">
Author
Owner

@JohnEstropia commented on GitHub (Jul 28, 2023):

even i update groups in Variant ImportableUniqueObject protocol, my Variant publisher will not be notified?

Yes, because the Variant.group instances do not change, which means the ListPublisher<Variant> will not have a difference.

I'm not sure how the fetchAll predicate is related to this observer and how it's behaving different depending on the predicate. Can you show what your predicate is for variantPublisher?

@JohnEstropia commented on GitHub (Jul 28, 2023): > even i update groups in Variant ImportableUniqueObject protocol, my Variant publisher will not be notified? Yes, because the `Variant.group` instances do not change, which means the `ListPublisher<Variant>` will not have a difference. I'm not sure how the `fetchAll` predicate is related to this observer and how it's behaving different depending on the predicate. Can you show what your predicate is for `variantPublisher`?
Author
Owner

@JohnEstropia commented on GitHub (Jul 28, 2023):

You're also using notifyInitial: true which will run the closure immediately. Are you sure that you are looking at the closure after the transaction?

@JohnEstropia commented on GitHub (Jul 28, 2023): You're also using `notifyInitial: true` which will run the closure immediately. Are you sure that you are looking at the closure *after* the transaction?
Author
Owner

@imrobbyrc commented on GitHub (Jul 28, 2023):

i see, thats why observer doesnt get notified. thankyou

sure, this my variantPublisher code, just fetchAll and sorting it
Screen Shot 2023-07-28 at 09 54 43

@imrobbyrc commented on GitHub (Jul 28, 2023): i see, thats why observer doesnt get notified. thankyou sure, this my variantPublisher code, just fetchAll and sorting it <img width="720" alt="Screen Shot 2023-07-28 at 09 54 43" src="https://github.com/JohnEstropia/CoreStore/assets/25898417/d82f10f1-c333-4afb-8114-e50752ac9e6b">
Author
Owner

@imrobbyrc commented on GitHub (Jul 28, 2023):

You're also using notifyInitial: true which will run the closure immediately. Are you sure that you are looking at the closure after the transaction?

i think the problem is not notifyInitial: true, because in first load i got a correct data, data will be break if i trigger variant update by using pull to refresh

@imrobbyrc commented on GitHub (Jul 28, 2023): > You're also using `notifyInitial: true` which will run the closure immediately. Are you sure that you are looking at the closure _after_ the transaction? i think the problem is not `notifyInitial: true`, because in first load i got a correct data, data will be break if i trigger variant update by using pull to refresh
Author
Owner

@JohnEstropia commented on GitHub (Jul 28, 2023):

I see. You should also be careful because sorting with relationship keys only work on the initial list, but not on updates. In general you should avoid relying on relationships when it comes to ListPublisher (NSFetchedResultsController) predicates because they are only reevaluated one level from the original Entity type

@JohnEstropia commented on GitHub (Jul 28, 2023): I see. You should also be careful because sorting with relationship keys only work on the initial list, but not on updates. In general you should avoid relying on relationships when it comes to ListPublisher (NSFetchedResultsController) predicates because they are only reevaluated one level from the original Entity type
Author
Owner

@imrobbyrc commented on GitHub (Jul 28, 2023):

I see. You should also be careful because sorting with relationship keys only work on the initial list, but not on updates. In general you should avoid relying on relationships when it comes to ListPublisher (NSFetchedResultsController) predicates because they are only reevaluated one level from the original Entity type

oke @JohnEstropia thanks for reminded me, do we have utilities for combine two observer in coreStore?

@imrobbyrc commented on GitHub (Jul 28, 2023): > I see. You should also be careful because sorting with relationship keys only work on the initial list, but not on updates. In general you should avoid relying on relationships when it comes to ListPublisher (NSFetchedResultsController) predicates because they are only reevaluated one level from the original Entity type oke @JohnEstropia thanks for reminded me, do we have utilities for combine two observer in coreStore?
Author
Owner

@JohnEstropia commented on GitHub (Jul 28, 2023):

There's no performant way to observe on relationships (i.e. foreign table) so my recommended approach would be to add a private field to Variant that your imported entity can update everytime the Group relationship is imported from it.

@JohnEstropia commented on GitHub (Jul 28, 2023): There's no performant way to observe on relationships (i.e. foreign table) so my recommended approach would be to add a private field to `Variant` that your imported entity can update everytime the `Group` relationship is imported from it.
Author
Owner

@imrobbyrc commented on GitHub (Jul 28, 2023):

There's no performant way to observe on relationships (i.e. foreign table) so my recommended approach would be to add a private field to Variant that your imported entity can update everytime the Group relationship is imported from it.

i see thankyou @JohnEstropia , i will research new approach before going to use your suggestion

@imrobbyrc commented on GitHub (Jul 28, 2023): > There's no performant way to observe on relationships (i.e. foreign table) so my recommended approach would be to add a private field to `Variant` that your imported entity can update everytime the `Group` relationship is imported from it. i see thankyou @JohnEstropia , i will research new approach before going to use your suggestion
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore#417