How to share one array with many view controllers iOS - ios

I value the opinions on this site and wanted to know what you all thought. I have an app that contains an array. This array is used in several view controllers. Currently, I create the array each time one of the view controllers opens up. I don't believe this to be the best thing to do. I have used NSUserDefaults before, and singletons, but am open to any ideas you have, plist, etc. I am looking on making things run quick and efficient.
Also, I wanted the user to be able to rearrange the array. Lets say it starts out in alpha order. But the user finds it better to rearrange it some other way. I know how to do that, rearrange, but I wanted to know where to keep the original array so that the user can than reset the order back to the original alpha order.
So I guess this question is twofold. Where to store the original array, and how best to then access the changed array throughout the app. Thanks very much for your help.
EDIT #1
I want to thank everyone for their comments and answers! This is what, I feel, the community is about. Learning new and different techniques is great. I am going to attempt to try all the answers (to see if I can actually program it) and see which one works the best for me. Once again thanks for this excellent dialogue.
Edit#2
I ended up doing a bit of both, and I would have never done that without all of your comments and answers. I made the array in the app delegate and saved it in user defaults. It wasn't a basic array, it was an array of custom objects so I had to use a bit of NSCoding. It also was not just alpha sorted, so I made one array that could be manipulated. Once again, thanks for all the great insight!

You can create a singleton instance of it in your AppDelegate.
Make an #property for the array in AppDelegate.h, and then import that header into your other viewControllers.
Init and store the array to the appDelegate's array #property in "didLoadWithOptions." You could create custom getters/setters to allow for manipulation. The actual data could come from an external XML, JSON or plist file, but to test you can just hard-code an array in AppDelegate to start with.
Each viewController needs to have a reference to the appDelegate, using the methods described in this answer. You can then access the 1 array as you would any other property,
NSArray *dataInVC = myAppDelegate.singletonArray; (...or using NSMutableArray if you want to add/change/manipulate).
...Alternatively, just have a separate class for your data, and create a singleton version of it so you can more easily refactor later if necessary. Examples of how to do this in this answer

As you are accessing your data from five different places, it will soon become confusing to send data to and fro. A singleton class with public properties storing your arrays would be a good solution to this problem.
In case you want to persist the data to disk, NSUserDefaults would be the better option.
Here's how one would go about using NSUserDefaults to do that. For saving data:
[[NSUserDefaults standardUserDefaults] setObject:originalArray forKey:#"OriginalArray"];
[[NSUserDefaults standardUserDefaults] setObject:modifiedArray forKey:#"ModifiedArray"];
Retrieving data:
NSMutableArray *modifiableArray = [[NSUserDefaults standardUserDefaults] arrayForKey:#"ModifiedArray"].mutableCopy;
Don't forget to save the data to disk with a call to [NSUserDefaults synchronize] at appropriate times.

I'd recommend storing the array in your app delegate. One of the advantages of this solution is that your app delegate is already a singleton.
Create an NSMutableArray property in your app delegate header file. Init and fill the array in the app delegate didFinishLaunchingWithOptions: method.
Access it from anywhere with the following code :
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
// appDelegate.myArray holds your values
Going even further, add this to your Prefix.pch file:
#import "MyAppDelegate.h"
#define appDelegate ((MyAppDelegate *)[UIApplication sharedApplication].delegate)
Then the previous code can be reduced simply to calling appDelegate.myArray from anywhere.
You can create methods that handle sorting and other manipulation on your array in your app delegate implementation. If you declare those methods in the app delegate header file, you can also call them from anywhere in the app with :
[appDelegate doStuff:parameter];

Related

Using an Array Variable in All Views

In an app that I am working for, I need array variable that can be used in all UIViews. Currently when the array is changed in a view it is stored in the database, and when I need the updated version of the array in the previous view, I use the viewWillAppear method and retrieve the updated array from the database. While going to another view by a segue, I use the passing data by prepareForSegue, but if I use the back button, or just change the screens via tab bar, I use the viewWillAppear and a query.
Is there any way that when the array is created in a view, the data in it will be accessible in all views?
As I've stated in my comment, singletons are generally frowned upon for a myriad of reasons. However, there is much debate on this topic:
What is so bad about singletons?
Having said that, the best way I know to make a variable globally available for the session is by creating a singleton.
struct myArray {
static var data: [Int] = []
}
You could set this singleton up to fetch the records using CoreData and store the current working version in a static variable for quick access.
note: I am really very curious to see some other approaches.
Singleton
Singleton is basically a global variable that you can use them in any views, but some developers experience some bugs and difficulties, use it at your own risk, I recommend this method when you're definite that you will use that data a lot (STILL RISKY), but this method is like goddess of data handling :).
Create a NSObject subclass and call it DataManager.swift (I call it data manager cause it handle data.) as following:
import UIKit
class DataManager: NSObject {
//Store Data Globally
static var someData: NSArray! //This Boolean, you can choose whatever you want.
}
the static is what keep your data live.
Now you can store and receive someData from anywhere like you handle any data type like this.
//Store
DataManager.someData = []
//Receive
print(DataManager.someData)

How to make a deep copy of an NSMutableArray property of a Custom Object

I have a CustomObject(of type NSObject) having an NSMutableArray property. This property contains NSDictionary objects. I need a deep copy of just the property to allow for editing in a different view controller; after editing, I desire to replace the original property with the edited deep copied property.
My question is:
Do I need to make a deep 'copyWithZone' ?
and if so, how do I implement it considering that it's just the single property that requires deep copying?
I've for now circumvented this by doing:
NSMutableArray *deepCopyArray = [NSMutableArray arrayWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:<CustomObject>instance.<propertyToDeepCopy>]]];
Although this works as NSMutableArray & NSDictionary implement NSCoding, it doesn't feel the right way, or is it? Kindly help :)
It's an acceptable way with multiple merits:
It works
It's simple and obvious
It's very little code
It's self contained and thus easy to change in future
Any alternative would mean you iterating over the contents and manually copying everything yourself, there are a couple of reasons you might do that:
You know what is truly immutable and you can avoid copying
You need mutable containers (yhe dictionaries in the array
Though even in some of these cases you'd want to run a similar archive based process just using a property list instead (so you continue to write minimal code and leverage supplied SDKs).

the best way to get access

I've got one variable and I need this variable during the whole programm. Now code is the next:
.h file
extern RequestParams* newUser;
.m file
RequestParams* newUser;
But it works bad. Information doesn't get to this variable.
What is the best way to solve this problem?
Thank you.
You will have to use NSUserDefault or Singleton to handle the values of varaiables accross various Controllers.
These both are used in such a scenario where you need to maintain and access the variable values across multiple View Controllers. You can opt for either one based on your choice.
NSUserDefault can store multiple key-value pairs that are accessible globally throughout the app. Singleton helps you create a object / variable which is static and hence no other instance of it is created afterwards. Only a single instance is retained throughout the app.
The following links might help you.
Singleton Tutorial
Another Singleton Guide
NSUserDefault Tutorial
Another NSUserDefault Tutorial
Hope this helps !
If you required only in you program then you can create it as singleton
// constants.h
+ (RequestParams*) newUser;
// constants.m
+ (RequestParams*) newUser{
static RequestParams* instance = nil;
if (instance == nil) {
// initiate your instance here;
}
return instance;
}
// you can Use it where you required
[constants newUser];
If you you want to keep to when application is closed then you need to use NSUserDefault to save it.
If this help you then you can accept it as solution.

iOS Pass data, singleton, extern or via protocols?

Hy all,
I am really stuck at data passing in my iOS app.
First i have a class with TabBarController and inside another two ViewController.
It's a container view with a daily and weekly calendar views.
And i wanted to store the downloaded data in an NSDictionary with dates, so the calendar don't have to reload the data any time (only if the user force refresh).
So, should i store this data in an "extern NSDictionary" in the Container view?
Or should i create a SingletonClass and store the Dictionary there?
But will the SingletonClass released after the container view get released?
Or should i store the NSDictionary in the container view and then use methods via protocols to access the Dic? But how?
I checked a lot of tutorials and examples but i still don't know how to do it properly.
Thank you
You could store it inside the tabBarController and access it inside of the tabBar viewController instances, but I think you might be best off by just storing it inside of the NSUserDefaults..That way you can easily grab it from anywhere in your application without grabbing the tabBar instance.
I'd personally recommend creating a Singleton class that implements your NSUserDefaults like so (although you can just write and read directly to it if you'd like):
//DefaultsSingleton.h
#interface DefaultsSingleton : NSObject
{
}
+(DefaultsSingleton*) sharedDefaultsSingleton;
#property(atomic,assign)NSDictionary *yourDictionary;
//DefaultsSingleton.m
#implementation DefaultsSingleton
SYNTHESIZE_SINGLETON_FOR_CLASS(DefaultsSingleton)
-(NSDictionary *) yourDictionary
{
return[ [NSUserDefaults standardUserDefaults] dictionaryForKey:#"your_dictionary"];
}
-(void) setYourDictionary:(NSDictionary *)yourDictionary
{
[[NSUserDefaults standardUserDefaults] setValuesForKeysWithDictionary:yourDictionary];
}
Then just import this singleton file to wherever you want to access it and you can init new dictionaries with the values of it and create mutable copies, and then override the saved value whereever you'd like. Oh and you should also import Matt Gallagher's awesome SynthesizeSingleton class. http://www.cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html

Objective-C iOS app not storing data in array of objects

this is a very hard question to ask because I don't want to flood you with all of my code, being that most of it is not pertinent to the problem. So I won't be to surprised if this goes unanswered. Although, it could be something hella simple that I am missing haha. Here it goes:
So my app is storing an array via [encoder] in my appDelegate. The app is full of objects that are creates in a separate NSObject class. Think of it this way for examples sake:
I have my main viewController class. And in appDelegate I define/encode an array of objects.
Now in my main, I fill the array with 10 "cars". My car class has variables such as color, make, model, etc.. Now when I save and relaunch the app, the array that I have saved is now an array containing 10 elements, but it seems to have forgotten all of the variables for each instance of the car class.
When I relaunch the app, If I call NSLog(#"%#",array in appDelegate); It prints 10 lines that look a lot like this:
""
So I know the array is being stored with 10 elements, and 10 elements are saved, but like i said, all of the variables are gone.
Note: On the first run of the app, and the array is being filled for the first time, I can access all the variables perfectly, and nothing is wrong.
Thank you for any help that I can get!!
We need to see the code for your implementation of initWithCoder and encodeWithCoder on the "car" class. If you haven't implemented them, that's your problem.
What is probably happening currently is that only the superclass implementation of these methods is being invoked. This means the correct class will be recreated but no data will be saved or restored.
NSCoding protocol reference doc.
Your main class as well as all the objects you put into the array all need to conform to NSCoding. If the objects in the array aren't NSCoding compliant, they won't get coded automatically.

Resources