how to record the order of a tableView managed by a NSFetchedResultsController - uitableview

I have an NSFetchedResultsController to display a tableView.
And users are allowed to change the cells' order.
How can I record the order so that when users go to the view again,
the table displays by the order modified by users last time?
Thanks a lot!

Hey guys I've done this.
In order to re-order managedObjects fetched by a fetchedResultsController, the most official way I think is to give the entity another attribute of int, such as "order", and give this attribute to the fetch request of a fetchedController, and in table view delegate method "move row from .. to " something like that, deal with this attribute with your hands, and if you use a fetchedController delegate, set a flag in that delegate methods to indicate that you will modity the entity yourself, and notify the delegate to do nothing but return.
Sample codes are Apple Sample code Recipes, and hints on the documentary of fetchedController!

Related

When to use a predicate over passing a CoreData object via the prepare method

I have an iOS app that I am currently building. I'm using CoreData for the first time and have a question in regards to passing data from one ViewController to the next. Right now I have a tableview set up in VCa, and when I tap a cell I want to get the details of that object (Person) in VCb. I have been thinking of doing this in 2 different ways.
Pass a reference of the Persons name in the prepage function. And over in VCb use a predicate to fetch that person back out of CoreData. Is using another fetch request the correct solution here. There will not be a ton of data in this app, so I don't think it would be very taxing on the system to do another request, but I'm new to CoreData.
Capture the data object in VCa and pass that object over to VCb via the prepare function. This would eliminate me having to do another fetch request in VCb but seems like I could be limiting myself for future expansions.
Again, I'm new to CoreData and just wanted some thoughts on which method of thinking is better and why.
Don't ever fetch an object that you have already fetched. In your case #1 you already have the object that you need, but you'd go ahead and fetch it again for no good reason. It might not be "very taxing" in your case but that just means you're probably not duplicating a lot of work for no reason yet, but it's still a bad design. And anyway-- this is an entity representing a person. Are you certain that there would never, ever be more than one person with the same name?
Your second idea is the better one here.

iOS: Design pattern for populating asynchronously fetched data

I am developing an app that fetches data from the web and displays it to the user. Assume that the data is reviews of a restaurant and one review is displayed on one view. The user can swipe left or right to go to the prev/next review. The data is fetched asynchronously (one thread for each review).
Here is the problem statement - Assume that 5 reviews have been fetched and the user is looking at the 3rd one currently. Now, the 6th review is fetched and I want to display it as the 4th review to the user (because the publish date of the 6th review is more recent than the 5th review). How should my model class inform the view controller?
I have considered some options -
Provide an array to the view controller and then send NSNotifications about new items to be inserted in-between the array at a specific index
Use an NSFetchedResultsController (this is a bit tricky because I am not using it with a table view controller)
View controller always asks for the next review to be displayed (from the model) and does not have a array of reviews with it
Are there any established design patterns that are employed in such a scenario? Other suggestions apart from the 3 above are welcome!
Just use an NSFetchedResultsController. When using NSIndexPaths just ignore the section. It's basically a glorified NSArray with free notifications.
Here's how I think I'd do it:
Make sure that the NSFetchRequest for your NSFetchedResultsController is sorted by publish date.
Handle NSFetchedResultsControllerDelegate methods.
When the NSFetchedResultsController updates, save the current object, reload the collection view, and then scroll to the saved object without any animation. This will appear to the user as if nothing happened to the current page.
While there is no perfect design pattern for every programming problem, the closest I can think of that relates to your problem is a combination of the Command and Observer patterns.
https://en.wikipedia.org/wiki/Command_pattern
The observer pattern is used in the NSNotification center.
While it's unclear as to why you'd want to skip a review, you could have two arrays to store them when fetched. The first holds all reviews that you have fetched. The second holds all reviews that are displayed.
Then you can get the last review in the fetched array, as if it were a stack. This way you always have the last one loaded displayed to the user.
I am confused why the order of display is different than the true order, ie why the 6th review comes before the 5th, but you asked about patterns to help.
Apart from MVC and observer, which are in the other answers and comments, I'd suggest using lazy loading with a virtual proxy. When reviews have been fetched, you can just display their proxy (eg with a "loading..." Message until they're fully in memory).
See more here: http://en.wikipedia.org/wiki/Proxy_pattern
I would recommend using the observing pattern to inform your controller than new data as been fetched. When receiving the signal, your view controller could update its array of "restaurant review" (either by adding the old one and reordering it according to some sort descriptors of your flavor or by querying the DAO directly).
Let's say you are fetching your data from internet and populating a CoreData entity with the results. Once you got your downloaded data you can populate your core data "Review" entity.
In order to "listen" at the change happening in core data, your controller should, in the viewDidLoad body, register itself as an observer for the NSManagedObjectContextDidSaveNotification.
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(updateInfo:) name:NSManagedObjectContextDidSaveNotification object:nil];
Then in your updateInfo, you can get the changes
- (void) updateInfo:(NSNotification *)notification
{
self.reviews = [self.managedObjectContext performRequest:myFetchRequest error:nil];
}

Why does my NSFetchedResultsController delegate stop firing when I add an NSPredicate?

I have an NSFetchedResultsController displaying "places" in a table view, but when I update the set of places that should be displayed in another view controller, my FRC does not update the table view.
That's the general problem. My specific case seems to revolve around the NSPredicate backing my FRC, because when I remove the NSPredicate (and just get all places), everything works fine.
My query is
#"ANY photos.isFavorite == %#", [NSNumber numberWithBool:YES]
places have a one-to-many relationship with photos (I am working through CS193P). Perhaps my FRC is not set up to observe changes in a related table or something?
A bit of additional information about my situation:
My Core Data updates and queries seem okay, as my "places" table is always correct when I first load the application.
My FRC does update rows that are already present at application load. It just won't insert new rows/sections at runtime.
I am only using a single MOC.
My sectionNameKeyPath is not set to a transient attribute.
My cacheName is set to nil.
I don't know if it's your case but I'll post anyway. Maybe it could be a valid workaround.
NSFetchedResultsController pitfall
Hope it helps.
Did you try testing a simpler predicate, for example using a photo one-to-one relationship instead of photos?
"my FRC does not update the table view" - Are you using -controllerDidChangeContent: ? Did you verify it is not getting called? I've seen that contrary to the documentation, calling reloadData on the tableView from within this method is unsafe, since the method may be called on a secondary rather than the main thread.
Are you performing all operations related to the MOC on the same (main?) thread?
Try this predicate instead?
#"%# IN photos.isFavorite", [NSNumber numberWithBool:YES]

Post-fetch sorting / Workaround for NSSortDescriptor + NSFetchRequest / Sorting a tableView

My quest to collect the scattered, magical pieces of code needed to create an animated and dynamically updating UITableView - artifacts hidden in the dark and ghastly depths of Apple Inc's feared dungeon, The Documentation - has with the help of the ever-friendly townsfolk and everyday heroes of Stack Overflow finally been completed.
But worry not, the end of this quest is but the beginning of a new one.
I have one UITableView. That tableView is hooked up to a NSFetchedResultsController. The FRC delegate methods are all up and running as pr. Apple's example code.
I have two NSManagedObjectContexts:
The Truth. This MOC is only inserted to / deleted from when the user adds or deletes an object.
The scratch pad. This is the MOC that the tableView's FRC is hooked up to. Any change here is reflected in the tableView with nice animations.
The scratch pad is seeded with objects from The Truth, but it is never saved. This means that I can insert and delete (show and hide) objects here to my heart's content, all while the tableView politely updates.
(To anyone reading this in an attempt to implement something like this I would say: get acquainted with [managedObjectContext objectWithID:id])
My question comes from the need to sort the tableView. As made clear to me by reading about NSSortDescriptor in conjunction with NSFetchRequest, using a sortDescriptor simply won't fly when one's using a SQLite store. The Docs say, "instead you should sort the returned array in memory". All-right then! But how do I go about doing that?
Where, in my logic as described above, do I inject this sorted array? Wherever I turn, there seems to be problems.

Update to NSManagedObject causes NSFetchedResultsController delete

I have quite a frustrating problem that I have been struggling with for quite some time.
To provide some context and detail I have an iOS UISplitViewController application - standard master / detail stuff. The master view is a UITableView backed with an NSFetchedResultsController (which loads NSManagedObjects from a SQLite data store).
What seems to be happening is that any update within the details view (which can routinely cause updates to the 'master records' and are flushed to NSManagedObject's and ultimately the SQL data store) causes a DELETE operation on the NSFetchedResultsController.
I assume that this is because the write to the NSManagedObject property(s) are causing a fault of some kind, which in turn causes the NSFetchedResultsController to expunge it from it's cached result set. The end result is that records go 'missing' from the master view (e.g.: UITableCellView's are removed from the master UITableView).
The issue is that I don't want this to happen and I have no idea how to stop it...
Has anyone experienced this issue before and could possibly provide some guidance?
Thanks in advance,
Ben
I'm not sure if this answers your question, but I figured out the solution to a similar problem I was having. I was sorting the objects in my Core Data-backed UITableView by the first letter of the name of each object. In whatever tutorial I read, it told me to put a transient property 'NameInitial' in the NSManagedObject subclass that I would populate with the first letter of the name of that object. I then used that property as my sectionNameKeyPath to sort the objects into the proper sections in my UITableView.
I had a button on each cell that updated a property of the object associated with that cell, and I properly received NSFetchedResultsChangeUpdate messages in my didChangeObject delegate function. HOWEVER, sometimes, cells would get deleted and I would receive the NSFetchedResultsChangeDelete message for no apparent reason.
Then I noticed that the cells that were getting deleted had (null) as the NameInitial property for their associated object. I had forgotten that the transient NameInitial is only stored in memory, and so is not necessarily maintained all the time. Once I manually repopulated the NameInitial property each time I updated a cell, the deleting stopped. So if you are using a transient property to help sort/section your UITableView, this might be your problem.
Hope this helps, and good luck!
-Rick

Resources