Sharing strings and variables throughout ios app - iphone

I'm making an app for a final project for class and I need to share strings, integers and floats throughout different views in my application. I have to create an app that a waiter/waitress would use on the job. I need different views for different types of items to order (beverages, appetizers, entrées, etc.) and need to keep the items chosen, the price and the quantity of each accessible to different views to keep a running total available in each view (one view for each type of item) and finally for a view that displays an itemized list of what was ordered plus the total.
From what I understand I wouldn't want to use a tab bar application layout because typically users don't expect information to be the same between different tabbed views, so I was thinking of using a segmented controller for this. To get the strings, integers and floats shared between views could declare them in the AppDelegate? I've read that I could use singletons but we haven't covered that in my class so I think that may just add more complexity than I need. If I were to declare them in the AppDelegate would I have to synthesize them in the AppDelegateViewController.m to make them available throughout? I can't imagine I'd have to synthesize them for each different ViewController. Or would NSUserDefaults be perfect for this situation?
If I declared an instance variable in the AppDelegate would that essentially make it a global variable? I know that this is against encapsulation practices but that won't make a big difference with this app, it's not going to be in the App Store and the overhead shouldn't make a big difference considering this is going to be a relatively small app.
Thanks in advance everyone. Good luck with your finals if you still have them approaching!
Edit
I guess I should say that this is going to be a janky, terrible app off the bat, we didn't cover a lot of the more advanced topics such as the MVC paradigm for iOS so I'm pretty limited with what I can do compared to what we're supposed to do. Stupid class, I regret signing up for it when I really could have gone about this myself and gotten a better understanding of Objective-C, which we were taught nothing about, and a better understanding of the iOS framework.
Basically, if I declare the variables in the AppDelegate, even though it's a faux pas, would that work to access the strings and such from the different views? Or would the NSUserDefaults be a better solution in this case? I'm leaning towards NSUserDefaults and declaring them in the projects ViewController.

A typical Objective C MVC solution is to put all your related shared strings and variables into a Model object (create a new class for this object) as properties. Then share that Model object with all the Controllers that need to access those variables or strings.
Using the AppDelegate as a model object is "over-sharing", and clutters up the app delegate with non-delegate related stuff. A slightly cleaner solution is to have the app delegate hold a getter to a Model object that is widely used throughout the app. A solution that can cause code reuse problems, and is otherwise considered politically-incorrect, is to assign the model object, and/or the shared variables themselves, to C global variables (be careful with your retains). (But this usually generates the fastest and smallest amount of code, if you care about such things.)

As hotpaw2 said, using a distinct model class is the best way to go.
But, as this is a small app (while you are learning the basics) implementing these few variables in the app delegate wouldn't hurt and is perhaps a little easier.
If the app grows then you'll probably want to move the model out of the app delegate and into it's own class.
An even easier and simpler method would be to store this small amount of data in nsuserdefaults:
save to nsuserdefaults:
[[NSUserDefaults standardUserDefaults] setObject:howManyDrinks forKey:#"howManyDrinks"];
[[NSUserDefaults standardUserDefaults] synchronize];
retrieve from nsuserdefaults:
NSString *howManyDrinks = [[NSUserDefaults standardUserDefaults] objectForKey:#"howManyDrinks"];

You can utilize the facility of Delegation pattern using Protocols in Objective C.

You could also store these values in a plist, which can then be accessed and edited from anywhere within the app. It is easier to implement than a singleton. And since you can set the plist up visually in XCode, it's relatively easy for beginners. I even created a wrapper for my plist to make editing the data simple. Here's a tutorial for plists.

I'm not an expert in this yet, but I've been using a singleton, with an object inside. As far as I have experienced, the values inside that object is held. To create a singleton, you'd do something like this:
Create a normal Object, and add this to the header file:
+ (id)sharedManager;
Then in the .m file, add this:
+ (id)sharedManager {
static SharedInfo *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init {
if (self = [super init]) {
self.myStuff = [[NSMutableDictionary alloc]init];
//This is where you initialise your variables. The example above is for a
//property that I have declared in the .h file
}
return self;
}
And then, throughout your app you'd use this:
[[[SharedInfo sharedManager] myStuff] addObject: SomethingTocreate];
Make sure you include the SharedInfo.h in the viewcontroller that you want to use it in.
I hope this helped.

Related

Using the AppDelegate to share data

I've found a couple of sources that explain how to use the AppDelegate to share data between objects in an iOS application. I've implemented it quite painlessly and it looks like a good approach in my situation. Thinking about what could be done using the AppDelegate, I am wondering where the line should be drawn.
Obviously there are other ways to share data across view controllers, use Singleton objects, and NSUserDefaults. When is it appropriate to use the AppDelegate to share data? In my current situation, I use this approach to store the appleDeviceToken used for push notifications. I use that token when users login or logout of the app.
In MyAppDelegate.h I declare the property:
#property (nonatomic, retain) NSString *appleDeviceToken;
In MyAppDelegate.m I synthesize appleDeviceToken and then set it:
#synthesize appleDeviceToken;
------------------------------------------------------
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
NSString *devToken = [[[[deviceToken description]
stringByReplacingOccurrencesOfString:#"<"withString:#""]
stringByReplacingOccurrencesOfString:#">" withString:#""]
stringByReplacingOccurrencesOfString: #" " withString: #""];
appleDeviceToken = devToken;
}
Then, in my LoginViewController.m I retrieve it and post it to my server:
NSString *urlForDeviceTokenPost = [NSString stringWithFormat: #"/api/users/%i/appleDeviceToken", userId];
MyAppDelegate *appDelegate = (MyAppDelegate*) [UIApplication sharedApplication].delegate;
NSString *appleDeviceTokenStr = appDelegate.appleDeviceToken;
AppleDeviceToken *appleDeviceToken = [[AppleDeviceToken alloc] init];
appleDeviceToken.deviceToken = appleDeviceTokenStr;
[[RKObjectManager sharedManager] postObject:appleDeviceToken delegate:self];
This works great so far, but is this the ideal approach? What else should I know?
When the data and objects are truly global and/or cannot be pushed further down the graph. Storage at this high level is usually not required. As well, your implementations should usually have little to no knowledge about the app delegate -- What's worse than a Singleton? The God-Singleton :) If the app delegate is complex, something's gone wrong. If the app delegate's interface is visible (via #import) to many of your implementations or they message it directly, then something is wrong.
There is no need for an (idiomatic ObjC) singleton -- there is one instance of the app delegate.
NSUserDefaults is for persistence of small values (as the name implies) -- the ability to share is a side effect.
Since the data is already sent into the app delegate by UIKit in this case, that may be a fine place to store the data, or an object representation of. You might also consider forwarding those messages to an appropriate handler. The important point -- In most cases, you would want initialization to flow down the object graph, and to flow from the lowest points possible (e.g. as opposed to many objects referring back to the app delegate). So you might see the app delegate set a top-level view controller's model, but the view controller can then set the models of the view controllers it pushes. This way you will reduce dependencies and control flow, cause and effect will be easier to trace, and you will be able to test it more easily -- free of the context of a massive global state.
The following line always indicates that you've done something wrong:
MyAppDelegate *appDelegate = (MyAppDelegate*) [UIApplication sharedApplication].delegate;
The application delegate is the delegate of the UIApplication. It is called that for a reason. It is not called the ApplicationDataStore or even the ApplicationCoordinator. The fact that you're asking the application for its delegate and then treating it as something other than id<UIApplicationDelegate> means that you've asked it to do something it isn't tasked with doing. It's tasked with managing the things UIApplication needs (which doesn't mean "everything the 'app' needs).
It appears that you've already built a place to store this information: RKObjectManager. I would have the app delegate pass the token there, and I'd have the login view controller just note that it is time to push it. I wouldn't even put the string #"/api/users/%i/appleDeviceToken" in the view controller. That's not related to displaying the view. That's something for you networking stack (which you seem to have housed in RKObjectManager). "ViewController" means "controller for helping display the view" not "processor of the operation that the view represents."
That seems like an appropriate use. The application delegate is tempting to misuse because it's an easily-accessible object that's already present in every app. It has a real purpose, though, which is, as its title indicates, to make decisions for the application object, just as a table view delegate does for its table view object.
In this case, you're storing information that was passed to the delegate from the application itself. I'd say that's where the line is drawn.
Storing this token seems to be in accordance with the app delegate's purpose, unless you had another controller object which was focussed on dealing with remote notifications. In that case, you would probably just pass the token right on to that controller.
I'm more pragmatic. Since the appDelegate in my app knows how the tabBarController was populated, and all the navigation controllers, I have several methods there that let some arbitrary class communicate with some other class - usually these are single instances of some class (but not singletons). That said, if what you want to put there does not have a compelling reason to be in the appDelegate, well, it probably doesn't belong there!

Sharing an object throughout an app

I am currently developing an application for the iPhone. The appdelegate shows a splash-screen while I'm caching data (e.g. NSDictionary) for use in a certain view. What is the best way to call this data from the view I need it in? I don't think passing it along as a variable from view to view until it reaches the view is a correct way to do this.
App Delegate (with Splashscreen that should cache the data to NSDictionary)
|
View A
|
SubView
|
Final View (here I want to use the cached data)
Thanks :-)
If the NSDictionary that you're caching the data in is an ivar of your App Delegate you can access it from anywhere in your app using the following lines:
myAppDelegate *delegate = (myAppDelegate *)[[UIApplication sharedApplication] delegate];
NSDictionary *myData = [delegate cachedData];
Hope that answers your question.
If you have an object that will never be released throughout the entire life of the app, and really want it to be accessible from absolutely anywhere in the app (say, so that a simple debug NSLog from absolutely anywhere in the code can print it's state), then that's what global variables are for. Just assign a global variable with a reference to the object. If you don't mind generating nearly equivalent but microscopically slower and larger code, then assign it to an instance variable in the app delegate with a suitable getter.
Note that using global variables is a violation of encapsulation that won't be very scalable, maintainable or suitable for unit testing, but is perfectly suitable for a small app which is not much larger than most objects would encapsulate anyway.

Why is everything a property in iOS SDK tutorials?

In most of the iOS SDK tutorials I've read online both from Apple and elsewhere, so many instance variables are made properties, even when they are only accessed from within their own class.
E.G. in Facebook's latest iOS SDK a user is encouraged to maintain an instance of the Facebook class called facebook in the app delegate. facebook" is a property. This is then referred to throughout the sample code as "self.facebook". But the "facebook" property is not referenced anywhere from outside the app delegate.
Why is this? What am I missing? If an instance variable is only used within its own class, my inclination would be not to make it a property so that it is not publicly visible, and refer to it simply as facebook rather than self.facebook or self->facebook from within the class.
Frankly, even if I needed the facebook property, I think I'd rather refer to it within the app delegate as simply "facebook" rather than "self.facebook".
So what gives? Why am I seeing properties everywhere?
Properties don't have anything to do with whether an iVar is publicly exposed or not. Instead properties create accessors methods that manage retention and foster encapsulation.
If you want a private property just declare the ivar under the #private directive and then define the properties in the implementation file.
One great example of why you should use properties (you can make properties private as TechZen noted), is creating new instances in viewDidLoad.
People do this all the time, because it's called once per instance of a view controller. Or, so you think... in reality because of what happens when you application gets a memory warning, a viewDidLoad class could be called multiple times per instance.
So for example you might well write code like:
- (void) viewDidLoad
{ myArray = [[NSMutableArray alloc] init]; }
Works great - until it's called again, then you have a leak. You could release myArray before you assign it just in case - but the trouble is that's an easy step to forget.
If you use properties for every instance variable though, then your code looks like this:
- (void) viewDidLoad
{ self.myArray = [NSMutableArray array]; }
Now you can't get it wrong. If viewDidLoad is called multiple times, the old array will be released and a new one will go in its place, without leaking the old array.
Usually it's better to access to the instance variable through an accessor, rather than directly. Properties create these accessors, and also provide things like proper key-value change notifications and atomic access.
Properties can generate getters and setters. Setters, in particular, can help manage retain/release counts of objects (semi)automatically, and thus reduce certain types of potential memory bugs.
Getters and properties for non-objects are mostly for orthogonality of coding style, although they do have potential to be used for mutators, key-value notifications, etc. in some future extension or reuse of the code.
There may be some efficiency differences/disadvantages, but that depends on the particular ObjC run-time in use.
if you refer to facebook, then it will access the variable directly, if you access self.facebook, then it will go through the setter/getter methods.
the result is that if you need to mutate an object or at somepoint later in time, you need to do other things during the process of changing the value(ie boxing it) then you can put this in the setter method and reduce having to do it everywhere. its a good thing.
It creates the getter/setter for you automatically.
Also, here is a good post explaining it properties

Design pattern for Core Data iPhone App

Im building an app that will use a Core Data model. I pretty new at Objective C and my usual design patterns does not really apply on Core Data and Objective C, at least I can't seem to find examples that confirms they will.
I have been through the Apple Developer examples and different sources on the intertubes.
It seems that to leverage Core Data I need to pass the managedObjectContext to each of my viewControllers, have the viewController implement the NSFetchedResultsControllerDelegate and then implement each of the methods for doing a fetch and subsequently implement
NSFetchedResultsChangeInsert
NSFetchedResultsChangeDelete
NSFetchedResultsChangeMove
NSFetchedResultsChangeUpdate
This adds approximately 100+ lines of code in each viewController and it is 90% the same code I write again and again. Plus I have to pass everything around and keep track of it's memory footprint.
In other languages I would build a singleton model of a few classes that held methods for maintaining and delivering data upon request, available from anywhere. It seems I can't take that approach in Objective C. If I where to build a static Class that took a managedObjectContext and returned me what I needed, I would still have to pass the managedObjectContext around to every view and it wouldn't be asynchronously like when I implement delegate methods that just gets called when a result is ready.
I hope this makes sense and that someone can either confirm that there is no other reasonable way to do it or help point me in a direction for wrapping this up in a good way.
Thanks:)
Core Data is not nearly as complicated as you describe.
Generally, an iPhone app has a "main" managed object context, which is generally owned by the app delegate. So long as you can get the app delegate (hint: [[UIApplication sharedApplication] delegate]) you have access to the managed object context. I like to define a static global variable to hold a reference to my app delegate to make life easier.
There's generally a one-to-one correspondence between NSFetchedResultsController instances and UITableView instances. Aside from populating table views, it's exceedingly rare that you would need an NSFetchedResultsController. If you have a number of similar views (e.g. a tab bar that lets you view the same data in different ways a la the iPod app), it would behoove you to create a single base class that configures the NSFetchedResultsController and derive your specific view controllers from that.
Now, when you create view controllers to edit an object, it's generally a good idea to do that in a separate managed object context. If the user cancels, you just discard the context and the changes go away. Again, you don't really need an NSFetchedResultsController for this because these views are only concerned with a single object.
When you're done editing, you save: the managed object context. The objects that manage your other managed object contexts should implement the NSFetchedResultsControllerDelegate methods to keep the table view in sync. Again, this can be implemented in a base class so you can generalize this functionality for related view controllers.
Do you absolutely have to use a CoreData model, or would something using a NSCoder (NSArchiver, NSKeyedArchiver, etc) work? I've found that CoreData is overkill for most applications.
Also, could you clarify why you can't take an approach using singletons? I've used singleton factories in a number of applications without issues. It's fairly easy to define class-level methods that operate on a shared (singleton) instance.

Application Design and AppDelegate

I am developing an iPhone app for some sweet undergrad research I've been working on. Sadly, my school doesn't offer software engineering / design classes so when it comes to questions of best practices in OO Design, I do a lot of reading.
My Dilemma:
My application loads a view (v1) where, upon user's button click, v1's controller class executes an action method. This action method should fill an array with objects. After that, the user will either execute the action again or click a different tab to load another view. Other views in the application will use the array that v1 populated.
So, where should this shared array be declared? Right now, it's in the AppDelegate class from when I was testing features without a GUI. Should I grab the AppDelegate singleton and add items to it in the v1ViewController? Should it be declared as static?
Thanks for the help!
^Buffalo
EDIT:
Follow-up Question: When interacting with a singleton, which is the better way to talk to it:
[[MyAwesomeSingleton sharedInstance] gimmeSomePizza];
or
MySingleton *s = [MySingleton sharedInstance];
[s gimmeSomePizza];
I guess what I'm wondering is, do you make the sharedInstance method call every time or do you define a pointer to the sharedInstance and then reference the pointer?
Using the app delegate to store data that's shared between views and view controllers is reasonable and appropriate.
In my apps, I view the app delegate as the controller part of MVC, with UIViews and view controllers all being part of the "view". I prefer to use a variant of MVC called Passive View that keeps the model and view parts of my app strictly segregated with only the controller connecting them.
I'm assuming that the array of objects you're storing is your app's model, so storing them on your app delegate makes sense. As Daniel D said, there's no need to make it static.
The app delegate is really the heart of your program. You create and initialize your model and views in your -applicationDidFinishLaunching: method and save your model data and view state in -applicationWillTerminate:. When your view controllers receive events that changes your model, you can call methods on your app delegate to make those changes.
You could store it in an ivar in the app delegate. You don't need to make it static since the app delegate is a singleton anyways (there's never more than 1 instance).
If the app delegate is getting a bit complicated, you can factor out the data storage into a separate model object or perhaps use Core Data.