views:

59

answers:

2

Ok here goes my setup:

Object Model:

* Category object is at the root  
* Product is linked to a Category (many-to-1)
* ShoppingItem is linked to a Product (many-to-1)

Application setup:

My application has a TabBarController at the root and a tableviewcontroller at the root of each of the tabs.

  • The first tableviewcontroller shows all ShoppingItems
    • It uses a NSFetchedResultsController to retrieve the data
    • The sortdescriptor for this controller is set as "Product.Category.Name"
    • The sectionNameKeyPath is set as "Product.Category.Name"
    • There's no predicate set
    • Cache name is set for this NSFRC
    • This helps me group the shopping items based on its product categories into sections.
  • The second tableviewcontroller shows all Products
    • It uses a NSFRC as well to retrieve the data
    • Sortdescriptor -- "Category.Name"
    • SectionNameKeyPath -- "Category.Name"
    • The predicate set is "Active == 1" - to load only active products
    • Cache name is set for this NSFRC as well
    • This helps me group the products based on its categories into sections.

Scenario:

  • When I change the category associated with a product through a third screen, the tableview which displays products refreshes itself appropriately, by reslotting the product into a different (and correct) section
  • But the same isn't happening on the tableview which displays the shopping items
  • It is not an issue with the predicates I guess, as the problem is not about missing items, it is more about the items slotted in the wrong section.

Both the tableviewcontrollers are setup the same way to be notified by the NSFRCDelegate when changes to section and row info happen.

Any clues as to what's happening here? Is this behaviour correct?

P.S. : Am @ work and not able to post code snippets. Can go home and do it, if that would help.

A: 

Caching could cause a temporary problem but if you make changes to the context, the cache should be refreshed automatically. You can test for this problem by deleting the FRC cache in the view controller's viewWillAppear method. That way when you come back to the view it starts with a fresh cache every time.

I think it more likely that you have two different managed object context. You have one context for the Product table and another shared by the Change-view and ShoppingItems table.

If the ShoppingItems table and the change-view share a context, then any alterations done in the change-view will appear automatically in the ShoppingItems table but the alterations will not appear in Shopping Items table unless you merge the context's changes.

If pretty much has to be separate context because the ShoppingItems can only get its category name by walking the relationship across the Product. If ShoppingItems shows the correct category but Product that must mean that each table is accessing different versions of each Product object.

TechZen
There's only one managedObjectContext that I use throughout the application - the one that is exposed by my AppDelegate. Is there a chance that the AppDelegate creates more than one object context, though I invoke the same property on it to get the context always?
Sara
No, if you are using the boiler plate code from the Xcode template you won't have more than one context. You can check for duplicate context by logging the context used by each view controller and see if they all have the same address.
TechZen
Incidentally, before reading your comment, I just did that and the objectContext used by both the controllers are pointing to the same object (same address)
Sara
Did you try deleting the cache? That's really the only thing left that I can think of.
TechZen
I have all the way been assuming that deleting the cache will definitely help, but was trying to understand why the cache is not being refreshed automatically upon the change. But to my surprise I now find that even after deleting the cache the notification is not instantaneous - I have to shutdown the simulator and restart it, for me to see the changes.
Sara
Interesting. Restarting the simulator often creates a new app folder name which scrambles pathways. Do you have some path hardcoded somewhere? Where is the store kept?
TechZen
Nopes - no hardcoded paths anywhere and I believe Coredata manages the sqlite store and cache by itself - I didn't have to mention the location anywhere explicitly.
Sara
If you use the Xcode template, then the store will be in the app's document folder and will be named `appName.sqlite`. Something is definitely non-standard here. You should see all the FRC sharing the same context update automatically. It should definitely update after deleting the cache. Some detail in your code is wrong.
TechZen
A: 

Strange problem, to say the least. Could it be that NSFetchedResultsController doesn't get notified of changes to section when using a section name key path of more than 2 levels ?

You could try the following workaround to check this point :

Add a readonly property named "categoryName" to your ShoppingItem class, with following implementation :

- (NSString *)categoryName {
    return self.Product.Category.Name;
}

Then, add the following method to your ShoppingItem implementation :

+ (NSSet *)keyPathsForValuesAffectingCategoryName {
   return [NSSet setWithObjects:@"Product.Category.Name", nil];
}

This will ensure that each time the name of the category changes, the KVO system will also trigger a change notification for categoryName, thus hopefully getting the NSFRC notified of the change. Of course, use categoryName as the sectionNameKeyPath of your NSFRC.

Let me know if this works.

Eric MORAND
No luck yet Eric.I tried adding the snippets you shared in the implementation file along with a property definition in the header file like this: @property (nonatomic, readonly, getter=categoryName) NSString *categoryName;I placed breakpoints in both the getter as well as the keyPathsForValues... method. While the one in the getter was hit for every item in the result, the one in the other method was never hit.I double checked if the names (including case) are as suggested. I even tried changing the static method name from ...CategoryName to ...categoryName, still in vain.
Sara