I have an app that had a TableView with customer information.
If a click on a cell I load the detail of this customer.
I'm using Magical Record to manage all my entities.
What I'm doing:
1) Load all the CUSTOMER entity on the viewDidLoad of my TableView.
2) User click to see the detail of the customer
3) Pass to the ViewController of the detail the object that represent the entity CUSTOMER (only one).
Everything works well.
The problem is, if the user select to reload the TableView I do this:
1) Go to the API to get all the customers
2) [Customer truncateAll]
3) Create all the entities back on CoreData
5) [[NSManagedObjectContext defaultContext] saveToPersistentStoreAndWait]
6) Reload tableview
BUT, if the user click to see the detail of the Customer during this process, the following ViewController show the customer information correctly for a while. Then after
[Customer truncateAll] occurs all the information dies.
How can I prevent this?
Many thanks!
You can make use of NSFetchedResultController to listen for your Customer entity changes. When your API call finishes and you create proper entities somewhere else in your app, you'll be notified in the controller about those changes and then you can reload the data. If you're not familiar with this concept look here.
Related
I'm working on a app with Firebase Database and I also want to allow the user adding entries when he's offline. Imagine the following case (everything offline; it works perfectly online):
The user adds a client (shown in a main tableview - works)
On the detail view of the freshly added client, he adds an appointment with him. The appointments are listed in a tableview in the Client Detail ViewController.
When the appointment is added, the tableview isn't refreshed, because the callback doesn't call.
In code:
navCont.child = userDB.child(entityNameClients).childByAutoId()
navCont.child?.setValue(post) where post is a dictionary with the values of the customer
On the viewDidLoad Method of the detail view controller, I call the following code: getUsersDBReference().child(entityNameAppointments).child(clientKey).observe(.value). The Callback isn't called (probably because there are no elements in it)
Adding Appointment
var appointment:DatabaseReference
appointment = getUsersDBReference().child(entityNameAppointments).child(clientKey).childByAutoId()
appointment.setValue(appointmentDict)
The Callback of 2 isn't called (--> and the tableview not refreshed with the new appointment)
BTW, I set Database.database().isPersistenceEnabled = true in App Delegates applicationDidLoad-method.
And if I add the client online and go offline then, it works too.
Answer of Firebase Support:
The SDK attempts not to fire Value events with "partial" data. Since you are only updating a subnode of the location being observed, we don't have "complete" data and so the observer is not fired. If the SDK has ever had "complete" data for that node (e.g. because you overwrote the whole node or because you were previously online and got complete data for it), then it will fire events when you update it.
One workaround would be to use ChildAdded (and ChildChanged, etc.) events instead of Value.
So I have a tabbed application. The first tab allows a user to enter information in ~20 fields that describe a NSManagedObject. They are then able to save this into core data, and that works just fine.
The second tab is a TableView of all of the existing submissions. Now when a user clicks on a cell in the TableView, it will open up the first tab and repopulate all of the fields that were originally saved into core data. When the user clicks save again, I want the existing submission in core data to be updated, instead of a new insertion into core data.
I have found a lot of information saying that I should make a fetch request and then update it like that. But that seems redundant to me because I already have the object that was saved passed to the first tab/ViewController.
If you could point me to some code that would help my situation or describe a way you might accomplish this scenario, I would greatly appreciate it!
Since you have a reference to the NSManagedObject in the first tab, you can update its properties to the new values when the user saves. You can then save the changes to your NSManagedObject (let's call it myObject for simplicity) by calling [[myObject managedObjectContext] save:&error] where error is an NSError *.
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];
}
My app will have a tableview with a picture and a title on each row, when the user taps it, it will open another view with that title, some texts and some pictures.
Now, I want each user to have different items in the tableview. For making it easier, suppose it is going to be a todo list like this:
Wash the car (Picture1) (video1) (InstructionsText)
Go to the groceries store (Pic2) (Vid2) (instrText2)
Pay the Bills (Pic3) (Vid3) (instrText3).
Now, I want to assign these items differently for each user, and show in a tableview.
USER 1 TABLE VIEW
Wash the car (Picture1) (video1) (InstructionsText)
Pay the Bills (Pic3) (Vid3) (instrText3).
USER 2 TABLE VIEW
Pay the Bills (Pic3) (Vid3) (instrText3).
USER 3 TABLE VIEW
Wash the car (Picture1) (video1) (InstructionsText)
Go to the groceries store (Pic2) (Vid2) (instrText2)
...
Now, here's my idea: each of these tasks should open a view controller with pictures, videos and text related to them. Using Core Data, I could create a modal, a entity called TodoList and attributes like title, text. First question: Can I create attributes for videos and pictures as well and store them here?
Suppose I have 500 different tasks, I will have to create a view controller for each, right? How would I relate these tasks to each user, like the example above? So each user would have his own tableview with the tasks leading to view controllers.
Assuming it is possible to make this work, how could I change the tasks assigned to each user directly, without having to use xcode or doing it programatically?
Use Core Data to store all your required fields in which image and video can also reside in Core Data. Use predicate to fetch the data according to constraints imposed on each user. When he will open the app, app should be able to fetch data according to user condition. After this you can load your table.
Hope this helps.
If we consider TO-DO apps , if a user should be able to see his own content , he will have to enter his own content through the app.This data is then stored in some backend either Core Data , SqLite or even cloud backend like Parse.com.Then the user is able to fetch his data , and see the contents in any view ...like tableView in your case.
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!