tags:

views:

297

answers:

4

I know this is a basic questing but I am just not finding a good answer. I have a app with multiple view controllers and I have noticed that if a create a variable and take action on it in one controller:

int foo = 0;
foo =+ 1;

I can declare the variable in another controller without initializing it's value it will carry the value it was last set to in the previous view controller:

int foo;
if (foo == 1)
    doSomething;

I have used this to my advantage for keep track of the current player in a multi player game etc... using the data in multiple controllers as their views are loaded and removed. I am new to Obj C and based on what I have been reading this does not seem like the right way to to things.

So here is my question, is this a safe way to pass data between controllers and if not what should I be doing?

+1  A: 

It sounds as if you are declaring a global variable (which C allows for), and it's not a recommended practice pass values around between view controllers.

You should have an object with your state, and pass that around to the controllers that need it.

pgb
+1  A: 

This is not a safe way to be passing information between controllers. If you are using this in your application, and it's working, I am actually very surprised.

The proper way to do this is to actually pass the value you need from one controller to the other. The example below uses the Application Delegate to store the value, and then each controller reads/writes to it... it's just an example, be careful about about using the Application Delegate as a repository for what become effectively global variables. Setting up lots of variables in the Application Delegate for use in this manner will make your application difficult to maintain.

In your App Delegate.h

@interface AppDelegate : NSObject <UIApplicationDelegate> {  
  int sharedInt;  
}
@property int sharedInt;

In your App Delegate.m

@synthesize sharedInt;  // this will automatically create the getters and setters

Then in the controller where you want to set the value:

ApplicationDelegateClassNameHere * applicationDelegate = [[ UIApplication sharedApplication] delegate];  
applicationDelegate.sharedInt = 3;

Then in the controller where you want to read the value:

ApplicationDelegateClassNameHere * applicationDelegate = [[ UIApplication sharedApplication] delegate];  
if (applicationDelegate.sharedInt == 3) {  
   //do your stuff here
}

Edited: forgot the @synthesize.
Edited: typed the return from the delegate singleton method, based on a suggestion from Kenneth Ballenegger, to eliminate the compiler warnings.

mmc
Thanks for the detailed answer since I am new to this the complete code really helps. I did implement this and it works great. Thanks,
Aaron
+1  A: 

I recommend doing (and do) something similar to mmc's answer. However, his answer will cause you to have a lot of warnings. You should make sure you're getting a AppDelegate * object, and not just any (id) object (like you're doing with mmc's method).

Just add a +singleton (or +sharedDelegate) class method to your delegate like so:

+ (iLaughAppDelegate *)singleton
{
    iLaughAppDelegate *delegate = (iLaughAppDelegate *)[[UIApplication sharedApplication] delegate];
    return delegate;
}
Kenneth Ballenegger
Excellent suggestion. I don't often use this pattern, and yes, the warnings would have gotten on my nerves.
mmc
Just did a little expirimentation, and it looks as if I type the reurn, rather than use id, the singleton method does not actually have to be within my delegate class... UIApplication handles it for me.Changing my code, with a note where I got the idea.
mmc
Yes, it'll work just fine. However, I believe you will still get a warning if you don't cast the return value before assigning it. In your suggested code, I would suggest you do: ApplicationDelegateClassNameHere *applicationDelegate = (ApplicationDelegateClassNameHere *)[[UIApplication sharedApplication] delegate];
Kenneth Ballenegger
A: 

This is fine if done correctly, but should only be done for readonly data. This is an extremely common way to share string constants. For example:

MyObject.h

extern NSString* const MyObjectWillChangeNotification;

MyObject.m

NSString* const MyObjectWillChangeNotification = @"MyObjectWillChangeNotification";

AnotherObject.m

#import "MyObject.h"
// You can now use MyObjectWillChangeNotification in this file

This same process will technically work for your int, but you shouldn't, as has been previously noted. It's much safer to allow any given variable be managed by one and only one object. Everyone else should get to it through an accessor.

Rob Napier