I have a question regarding sharing a model's state between View Controllers.
Let's take an example: the Twitter app. In the timeline feed, you see a list of statuses, which are loaded from the API, serialised as models. And in the mentions feed, you also have a list of Statuses. They also are loaded from the API, serialised as models, but as different instances. If a user taps the heart button on the mentions feed, it should show up as a liked tweet in the timeline feed as well. But that means sharing the state of two different model instances that represent the same status update.
The approach I'd take to solve this inconsistent state is use a "cache" of Statuses. I'd put it in the Status model as a static property, like so:
static var cache: Array<Status> = Array<Status>()
and use helper methods to always use a single instance for each post, no matter from what view controller they are loaded/modified.
Is that anti-pattern? Is there a better way to do it?
Just to rephrase first.
Get API A returns arrayA[ X, Y, Z]
Get API B returns arrayB[M, Y, F]
View controller A shows array A
View controller B shows array B
Objects are not persisted
User modifies Y in View controller A, but view controller B does not show update.
Option 1: Put all objects into one array and add a mechanism to know
which should be displayed in A and B view controllers
Option 2: When update in either array occurs, update other array if
element exists
Option 3: Get API A and Get API B handlers store results in arrayC or
dictionaryC, but also maintain arrayA and arrayB. However A and B no
longer hold instances of objects, rather references to the objects in
arrayC or dictionaryC. This is really just an implementation of
option 1. I'd got with a dictionaryC where key is the uuid of the object stored in value, and array A & B just store keys.
Sure there are other options, like sending a notification so other view controller knows to refresh data.
I don't think you should go down the road of keeping different instances in sync though.
If I'm not mistaken Twitter use Firebase, so autoupdating is just thanks to live observing of database. You should probably think about observing changes in your objects and update collections that your views are basing on appropriately. I don't know your exact architecture though.
Related
I'm sort of learning on the fly (coming from a desktop perspective), so forgive me if this seems dumb.
This would be a CRUD type of application, so imagine if you have two controllers for data entry:
SupervisorController
EmployeeController
Now, let's say the User goes to https://whatever/SupervisorController and before I do anything, I need to create some objects specific to the Supervisor screen (e.g. I create an Access object, which reads some data from a source, which tells me what they have access to on that specific Supervisor screen).
OK, in my Index method I construct that object and pass it to my view. But, that object won't persist when say, another method for that controller is called, or say Refresh on the browser is clicked (the constructor for the controller is called each time).
And let's say that the user goes to the browser and types https://whatever/SupervisorController/AnotherMethod themselves. Well, I only constructed that object in my Index Method. So now I have to construct that same object, again, there? And pass it to this view?
Where I'm getting at is that if someone goes to any method of the SupervisorController, if the object isn't there, I want to construct some "supervisor" specific objects, keep them available in my "private member variables", until I'm done with SupervisorController. Meaning, if they move on to say EmployeeController, those objects can now go away.
At EmployeeController, I'll want something similar. Complex objects created specifically for Employee CRUD, that I won't need once I'm done with Employees.
I mean, I really don't want to create these objects and store them in the Session for the lifetime of the session, as they are really only needed for their specific controllers. On top of that, how much data do I really want to be storing in session memory before it gets to be too much!
But if I don't store them somewhere, I would have to re-create these objects for every action/method. I don't want to create them in every method of a specific controller (I could be going to a database to get some specific information). For example, I'm playing around with a Grid Control on my Index page, and when you reach that page, there's the initial call to the Index method, and then the grid itself makes a call to this Read method I have. So I would be creating that object twice!? On one call to https://whatever/SupervisorController?
How do people handle what I'm trying to achieve? Or is there some way I need to look at it now, and implement it to those guidelines?
There are different levels I'm asking this question at.
Case 1: Let's think about the typical drill-down design. Say a table view controller has an array of custom objects, and tapping a cell will push a view controller that allows the user to modify the object represented by the cell. In this case, should the pushed view controller have the custom object as a property of its own, or use a data source/delegate protocol to edit the custom object but not own it.
Case 2: A similar but slightly different situation is this. I'm using a singleton store to handle an array of bank accounts in my app. A view controller will show a list of the accounts, and I'm wondering if I should have the array of accounts as a property in my view controller or get the array via the store. (The array of accounts is accessed quite often.) I guess the only difference is a single object vs. an array of objects. I'm curious about how heavy these arrays can be, so whether it's faster to load the array from the store each time or have it as a property in the view controller.
Case 3: When should the local file system be used? In my app's example, bank accounts are accessed quite often, so I have them unarchived and set as properties upon launching the app, but for much bigger data, I only load them from the file system when they should be displayed or edited. I'm still not sure what the right way is.
I am converting an app to use Core Data from previously just being in-memory objects. This app fetches data from a remote API and, previously, created objects in memory with an incrementing ID and I figured out which direction the user was navigating (turning pages) in based on whether this incrementing ID was getting larger or smaller. And based on that populated child view controllers (being given to the PageViewController) with the correct info. The object selection logic was in the didFinishAnimating pageViewController delegate method because it was only called once per page transition.
Now I'm storing some objects in Core Data and I need to know what is "next" and "previous" in order to properly set the next and previous view controllers being fed to the PageViewControllers. As before I'm fetching from a remote API but now creating Core Data managed objects based on the data retrieved from the API.
I could make my own incrementing counter field in Core Data but I wondered if there is a better way to do this? I don't want to use Core Data like a RDBMS.
More generally - how are people using Core Data to power PageViewController apps with a dynamic object collection with potentially no "last page"?
Note: This project is written in Swift.
It turns out the API I am speaking to (MediaWiki category enumeration) can return results in a timestamped fashion - I can use these timestamps as a way to determine in which direction I am going. So the lessons from this is :
See what facilities the remote API has to determine result ordering; in this case chronological ordering fit the bill.
If the results are truly un-ordered and coming from a remote source then you'll have to apply some kind of local ordering so that paging works predictably.
Store the results in an array. Pass the array (and the object to display) from one view controller to the next (dependency injection). The view controller can ask the array what index the object is at and adjust from there.
My question is how to implement this correctly and with good design.
I would use Core Data for this.
Problem description:
Let's suppose that we have two object types (classes) in the system, Location and Event. They are retrieved from webservice, and there is no need to persist it.
Any of these two kind of objects can be added (saved) to favorites and it should be persisted locally.
Additional requirements:
show and manage favorites - let say in FavoritesViewController (I would use here NSFetchedResultController)
display (cell) of favorites is different, according to favorite type (location or event)
in Location/Event details view controller, there will be an action to add/remove to/from favorites, and the state of that action should be set according to favorites existance
in the future, it can be another object type which can be added to favorites (for example, Drink).
I have a dilemma about the best way to implement this. Should I store locations and events directly as separate entities (model objects), and somehow retrieve it in a single fetch, in order to get and manage the list of favorites. Or, maybe use an interface/protocol (for example Favorable), and create and store Favorite objects, and each object which can be added to favorite should implement favorable and will be converted to Favorite object, but in this case, it will limit favorites to only attributes that Favorite object exposes.
You should make a simple Core Data model with the two entities. It is very straight forward. Your table view would have two type of cells (with different identifiers) that display the data as needed.
You can use these to entities (subclasses of NSManagedObject) throughout your app. You should perhaps persist them anyway (so they are available if the internet goes down and allow the user to continue working with them). The favourite instances can be marked with a BOOL property.
One design consideration, though: maybe you want to create an optional relationship between Location and Event. Some events might be tied to a particular location and you will need this info as well. With Core Data this is really easy to do.
I have an application that is mainly a heirachy. Object A has many object B's and Object B has many Object C's.
I display them in my iOS application via a navigation type application, and A is on the front page, you push to the B's and push to the C's.
I want to be able to save each instance of my A, B, C objects (which are custom classes) but I'm not too sure when to save and read them as the table view displaying data about A, B and C need to be populated when/before that view is pushed.
Should I be reading it out in didSelectRowAtIndexPath? or something else? and what about saving? should that take place during tapping back or some other place? in the class itself perhaps?
Sam
You should probably save whenever the user finishes an edit.
You should get your B's once you need them, etc. When the user taps on a row in the table view that displays all the A's, then get the B's that relate to that particular A object. You have two options here: (1) Fetch them with an NSFetchRequest / NSFetchedResultsController or (2) traverse the A object's to-many relationship that points to the B objects for that A objects.
As for saving: Note that saves might take a while if you've edited a lot. There are some advanced techniques you can use with iOS 5 with nested contests (-parentContext) which allow you to save on a different (non-main) thread. You have to make sure, though, that your safe completes before you're suspended, because the system is allowed to kill your process while you're in the background.