iOS Best practice for handling model objects - ios

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.

Related

Swift/iOS - Sharing Model State between View Controllers

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.

How do I save values from the child view controllers of a UIPageViewController to use elsewhere in an app?

I have a UIPageViewController containing multiple view controllers each with questions for the user to respond to. Once these questions are answered I want to save the values somewhere locally so I can later create a PDF populated with these values. What is the best way to do this? Would I use NSUserDefaults?
It depends on how you want the data to persist. If you want the data to persist the life of the user, even if the app is deleted from the device, you would obviously need to store it away from the client such as in a database (i.e. Realm, CoreData). If you want the data to persist the life of the app itself, data that you would continue to use to shape the user's experience, you could use UserDefaults but that doesn't seem like what you're trying to do. And if you just want the data to persist the life of that instance of the app, store it in regular properties.
I suspect, for whatever reason, the third option would be your choice. If so, I would suggest creating a model object that's as an instance property of the parent view controller (that all page view controllers can reference)...
class SurveyAnswers {
var userName: String?
var userAge: Int?
var favoriteSauce: PizzaSauce?
var livesWithCats: Bool?
}
...and simply use the protocol/delegate pattern to pass data from the child to the parent which would update properties in that object (so long as they are updating the same instance of that object). Then, when you're ready to prepare the PDF file, simply ask the parent for that object, whose properties have been set by the child view controllers.
And if you're OK with it, you could use the shared AppDelegate as a way to store and retrieve this data. I would just caution against making this a habit but depending on your application as a whole, this may be a perfectly acceptable option.
General rule of thumb: set properties in destination objects to pass data forward and use delegates to pass data backward.

PageViewController : Determining "next" and "previous" when using Core Data

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.

Access NSArray from multiple views

I have a data controller class used within my app that handles parsing xml and a few other operations vital to my app. What I want to be able to do is have the data that it parses store in an array that can be accessed in multiple views of my app. Right now, each view creates its own instance of the data controller class and so the array that the data is stored in is specific to that view controller. Is there a way to still create individual instances of the data controller class for each view controller, but the data is stored in the array where all views can access it? I have tried to store in NSUserDefaults but that doesn't seem the most effective way. Each view controller needs to have its own instance of the data controller class because I utilize delegate methods that are used in each of the view controllers. I hope this makes sense.
You have two ways to implement this (ok, maybe more than two but those are most common):
Store array in application delegate and acces it as property.
Create singleton object who gonna hold array (and other possible data/methods).

iOS: Nesting arrays in a second view controller - use objects?

In my app an NSArray is created to store various results from a library search. The idea is that each NSArray of results should also be stored locally so that if the search is made again in the future the local results are retrieved.
Now, I've been thinking about two different approaches. The first is to simply make an array in the second view controller that stores the different results arrays. The second is to instead make a class called Search (for example) that has an NSArray attribute to store the results. This object would be initiated in the second view controller (which would then add it to its own array).
Does this make sense? In terms of memory management is one better than the other? Also, I'll need to use the delegate function to get the data across to the second view controller, right?
Thanks
I personally don't see a big difference. To clarify on the second option, create a singleton object that your Search class makes available to any client class (the view controllers). That singleton provides a store function and a retrieve last result function.
You can make this even simpler by just using the class itself - class methods to store and retrieve, and the class then uses a static NSMutableArray (or NSArray) to keep save the objects.
If you want to make this array available across restarts, then use NSUserDefaults. If things in your array cannot be saved in defaults (some objects cannot) you can possibly turn the array into a NSData object and store that (if all objects comply with NSCoding you are in good shape.

Resources