I load a few variables in my appdelegate class. They are declared in my .h file.
I have a global.h file that declares the same vars as extern, such as:
appdelegate.h
NSString *DBName;
global.h
extern NSString *DBName;
I haven't found the pattern yet, but some of the classes I include the global.h but the var is nil.
Any idea what I am doing wrong?
EDIT:
It looks like the vars that are like:
int x;
stick and are available,
but the vars that are pointers get lost:
NSString *Name;
They are all loaded initially from a DB in the appdelegate.
I also tried declaring
char Name[30];
then assigning it and all is good.
Now what?
In a .h:
extern NSString *global;
In a .m somewhere:
NSString *global = #"foobar";
If you need to set the global at runtime, you'll have to do so in a method somewhere; say, applicationDidFinishLaunching:.
Where are you assigning to the global in the NSString case? And when you do are you retaining the value? What do you mean by "lost"?
Note that the variable must not be declared in a .h; the extern goes in the .h, the NSString *global; must be in one and only one .m file.
What kind of variables are your working with? Are they primitives or objects? If they are primitives, you might think about preprocessor define statements rather than global variables.
If they are objects, you may want to create an implementation of your Global class, and use a Singleton instance to serve and set the variables. Something similar to this
#implementation Global
static Global *myGlobal = nil;
+(Global *)sharedInstance
{
if (myGlobal == nil) {
myGlobal = [[self alloc] init];
}
return myGlobal;
}
#end
Then you can call the variables using:
[[Global sharedInstance] variableName]
Problem was the NSStrings were not retained. #xianritchie suggested this in the comment above. I changed the few global strings I have an now all is good.
Thanks all for the help
Related
Hey I'm very new to Objective C programming and I'm stuck. How come when I create I function, it can't use the variables I created for the labels or textviews, etc. And whenever I call them in the viewDidLoad function, I have to do either self.(variableName) or _(variableName) and it won't let me do that outside of the viewDidLoad function. Is there a way to access them outside of it?
How come when I create I function, it can't use the variables I
created for the labels or textviews, etc.
For one thing, you need to differentiate between a function and an instance method. In Objective-C, classes can have instance variables (variables that are part of an instance of that class) and instance methods (similar to functions that are associated with an instance of that class). Classes can also have properties, which are used rather like instance variables in that they're values associated with an object, but they're accessed through accessor methods. Functions, on the other hand, aren't part of any class. So, a class has an interface where instance variables and methods are declared, like this:
#interface Person : NSObject
{
NSString *firstName;
NSString *lastName;
}
#property (readonly) NSString *fullName;
#property (strong) NSArray *friends;
#property (assign) int age;
- (id)initWithFirstName:(NSString*)first lastName:(NSString*)last;
- (void)addFriend:(Person*)friend;
#end
And also an implementation, like this:
#implementation Person
- (id)initWithFirstName:(NSString*)first lastName:(NSString*)last
{ /* code goes here */ }
- (void)addFriend:(Person*)friend
{ /* code goes here */ }
- (NSString *)fullName
{ return [NSString stringWithFormat:#"%# %#", firstName, lastName; }
#end
Those things in the implementation are instance methods, as denoted by the - at the beginning and the fact that they're defined in an #implementation block. (If they had + instead of -, they'd be class methods instead of instance methods -- I'll let you read about that in the docs.) Properties are accessed by calling an appropriate accessor methods using either normal method calls or dot notation, so if you have:
Person *george = [[Person alloc] initWithFirstName:#"George" lastName:#"Bailey"]
all of these are valid:
NSString *name1 = george.fullName;
NSString *name2 = [george fullName];
george.age = 45;
[george setAge:45];
int years1 = george.age;
int years2 = [george age];
Also, self is a pointer to "the current object". You can use it in instance methods so that objects can call their own methods and access their own properties. For example, the Person class could contain a method like this:
(NSString *)nameAndAge
{
NSString *nameAndAge = [NSString stringWithFormat:#"%#: %d", self.fullName, self.age];
}
Functions, on the other hand, aren't part of any class, use C function syntax rather than Objective-C method syntax, and aren't defined in an #implementation block:
BOOL isMiddleAged(Person* person)
{
return (person.age > 30) && (person.age < 60);
}
You can't use self in function because a function isn't associated with an object, so there's nothing for self to point to. You can, however, use properties of other objects you know about, such as person.age in the example above.
And whenever I call them in the viewDidLoad function, I have to do
either self.(variableName) or _(variableName) and it won't let me do
that outside of the viewDidLoad function.
You must be accessing properties of your view controller. As explained above, self.(variableName) is the way to access properties. _(variableName) refers to a variable (often generated by the compiler) that stores the value of the property. (You shouldn't normally access those variables directly outside initialization methods and -dealloc -- use the property accessors instead.) You can use those properties in any instance method of the class, not just -viewDidLoad. You can also access properties of other objects by replacing self with the name of a pointer to the object, just as I did with person in isMiddleAged().
Seems like your are using autosythesized property. Using Auto Synthesized property you need not to #syhtesize objects.
#sythesize object = _object; will be implicitly implement in this case.
So you can access object using self.object or _object.
You can #synthesize to avoid using objects via self.varName or _varName .You can directly use it using varName.
Header file:
NSString *righta;
#property(nonatomic, retain) NSString *righta;
(I don't usually make #property declarations for my variables but thought this might help the variable persist through the class, though it hasn't)
Implementation file:
#synthesize righta;
- (void) function1 {
righta = [NSString stringWithFormat:#"A"];
}
- (IBAction)function2:(id)sender {
NSLog(#"righta is still %#", righta);
}
On trying to access the value of the string in the second function, I receive an "EXC_BAD_ACCESS" and the app crashes.
Any help would be GREATLY appreciated.
Thanks!
stringWithFormat returns an autoreleased object. You must retain it. Note that you are accessing the ivar directy, not the property so the string is not getting retained. Use the property instead:
self.righta = [NSString stringWithFormat:#"A"];
Some programmers prefer to synthesize their properties with a different ivar name to avoid accessing the ivar directly by mistake.
#synthesize righta = righta_;
You must use
self.righta = [NSString stringWithFormat:#"A"];
To assign the variable otherwise the accessor is not used and the value is not retained.
Change function1 to:
self.righta = [NSString stringWithFormat:#"A"];
You were assigning directly to the righta ivar without retaining the string.
Here is a simple one for you guys . I'm defining a class to store variables in so I can reuse those variables in different ViewControllers .
Here is how I do it, it`s obviously not working ( that's why I'm asking a question ... ):
I declare a class :
VariableStore.h
#interface VariableStore : NSObject {
int evTe;
}
#property (nonatomic) int evTe;
+ (VariableStore *)shareInstance;
#end
VariableStore.m
#implementation VariableStore
#synthesize evTe;
+ (VariableStore *)sharedInstance {
static VariableStore *myInstance = nil;
return myInstance;
}
#end
Now in my FirstViewController I want to set the value for evTe :
[[VariableStore sharedInstance] setEvte:2];
NSLog(#"value testing, %i", evTe);
And this keeps on returning 0 unfortunately, Im obviously missing something important here but I can't figure out what it is .
Later on Id like to set the value for evTe here in the FirstViewController and then reuse it back in the SecondViewController ..
You are setting your shared instance to nil and then returning it:
static VariableStore *myInstance = nil;
return myInstance;
A nil instance won't hold your variable. It's nil.
First off you shouldn't be using a singleton to pass around variables. If you're going to do that then you might as well just use global variables instead (don't do that either by, the way). Second, if you insist on using a singleton, you need to read up on how to use them.
Finally, if you want to pass variables between view controllers, you either need another view controller that is a parent to the two to facilitate passing data between them, or one needs to call the other and take the first one or its data as a parameter.
Well, you're asking for the value of evTe without calling the object to which it belongs. Try this:
NSLog(#"value testing, %i", [[VariableStore sharedInstance] evTe]);
If you keep using the singleton for a number of times, you might want to do:
VariableStore *vStore = [VariableStore sharedInstance];
so you can do:
[vStore setEvTe:2];
NSLog(#"value testing, %i", [vStore evTe]);
And look out for what Matt said about nilling your singleton ;)
I think in nslog you should output not just evTe, but [[VariableStore sharedInstance] evTe].
First, you have to declare the static variable outside the function, in a way both controllers can access.
static VariableStore* myInstance = nil;
The singleton sharedInstance should be:
if(myInstance == nil)
{
myInstance = [[VariableStore] alloc] init];
}
return myInstance;
I am new to iPhone development. I want to access a string variable in all the class methods, and I want to access that string globally. How can I do this?
Please help me out.
Leaving aside the issue of global variables and if they are good coding practice...
Create your string outside of any Objective-C class in a .m file in your project:
NSString *myGlobalString = #"foo";
Then put the declaration in a header file that is included by every other file that wants to access your string:
extern NSString *myGlobalString;
OK, well I can't leave it entirely aside. Have you considered putting your "global" string somewhere else, perhaps inside your application delegate as a (possibly read-only) property?
The preferred methods for creating a global variable are:
Create a singleton class that stores
the variables as an attributes.
Create a class that has class methods that return the variables.
Put the class interface in the
universal header so all classes in
the project inherit it.
The big advantage of method (2) is that it is encapsulated and portable. Need to use classes that use the global in another project? Just move the class with the variables along with them.
You can achieve that by implementing getter and setters in the delegate class.
In delegate .h file
Include UIApplication delegate
#interface DevAppDelegate : NSObject <UIApplicationDelegate>
NSString * currentTitle;
- (void) setCurrentTitle:(NSString *) currentTitle;
- (NSString *) getCurrentTitle;
In Delegate implementation class .m
-(void) setCurrentLink:(NSString *) storydata{
currentLink = storydata;
}
-(NSString *) getCurrentLink{
if ( currentLink == nil ) {
currentLink = #"Display StoryLink";
}
return currentLink;
}
So the variable you to assess is set in the currentlink string by setters method and class where you want the string ,just use the getter method.
All the best
I posted an article about my methodology for doing this:
http://www.pushplay.net/2011/02/quick-tip-global-defines/
This is something I primarily use for notification keys. Creating a globals.h file and adding it to the (your_project_name)_Prefix.pch file will ensure it is accessible globally...
I'm trying to understand how strategies some folks use to distinguish instance vars vs. properties. A common pattern is the following:
#interface MyClass : NSObject {
NSString *_myVar;
}
#property (nonatomic, retain) NSString *myVar;
#end
#implementation MyClass
#synthesize myVar = _myVar;
Now, I thought the entire premise behind this strategy is so that one can easily distinguish the difference between an ivar and property. So, if I want to use the memory management inherited by a synthesized property, I'd use something such as:
myVar = #"Foo";
The other way would be referencing it via self.[ivar/property here].
The problem with using the #synthesize myVar = _myVar strategy, is I figured that writing code such as:
myVar = some_other_object; // doesn't work.
The compiler complains that myVar is undeclared. Why is that the case?
Thanks.
Properties are just setters and getters for ivars and should (almost) always be used instead of direct access.
#interface APerson : NSObject {
// NSString *_name; // necessary for legacy runtime
}
#property(readwrite) NSString *name;
#end
#implementation APerson
#synthesize name; // use name = _name for legacy runtime
#end
#synthesize creates in this case those two methods (not 100% accurate):
- (NSString *)name {
return [[_name copy] autorelease];
}
- (void)setName:(NSString *)value {
[value retain];
[_name release];
_name = value;
}
It's easy now to distinguish between ivars and getters/setters. The accessors have got the self. prefix. You shouldn't access the variables directly anyway.
Your sample code doesn't work as it should be:
_myVar = some_other_object; // _myVar is the ivar, not myVar.
self.myVar = some_other_object; // works too, uses the accessors
A synthesized property named prop is actually represented by two methods prop (returning the current value of the property) and setProp: (setting a new value for prop).
The self.prop syntax is syntactic sugar for calling one of these accessors. In your example, you can do any one of the following to set the property myVar:
self.myVar = #"foo"; // handles retain/release as specified by your property declaration
[self setMyVar: #"foo"]; // handle retain/release
_myVar = #"Foo"; // does not release old object and does not retain the new object
To access properties, use self.propname. To access instance variables use just the instance variable's name.
The problem with using the #synthesize myVar = _myVar strategy, is I figured that writing code such as:
myVar = some_other_object; // doesn't work.
The compiler complains that myVar is undeclared. Why is that the case?
Because the variable myVar is undeclared.
That statement uses the syntax to access a variable, be it an instance variable or some other kind. As rincewind told you, to access a property, you must use either the property-access syntax (self.myVar = someOtherObject) or an explicit message to the accessor method ([self setMyVar:someOtherObject]).
Otherwise, you're attempting to access a variable, and since you don't have a variable named myVar, you're attempting to access a variable that doesn't exist.
In general, I name my properties the same as my instance variables; this is the default assumption that the #property syntax makes. If you find you're fighting the defaults, you're doing it wrong (or your framework sux, which is not the case for Cocoa/Cocoa-touch in my opinion).
The compiler error you're getting is because property use always has to have an object reference, even inside your own class implementation:
self.stuff = #"foo"; // property setter
[stuff release]; // instance variable
stuff = #"bar"; // instance variable
return self.stuff; // property getter
I know that many Cocoa programmers disagree, but I think it's bad practice to use properties inside your class implementation. I'd rather see something like this:
-(void) someActionWithStuff: (NSString*) theStuff {
// do something
[stuff release];
stuff = [theStuff copy];
// do something else
}
than this:
-(void) someActionWithStuff: (NSString*) theStuff {
// do something
self.stuff = theStuff;
// do something else
}
I prefer to do memory management as explicitly as possible. But even if you disagree, using the self.stuff form will clue in any experienced Objective-C programmer that you're calling a property rather than accessing an instance variable. It's a subtle point that's easy for beginners to gloss over, but after you've worked with Objective-C 2.0 for a while, it's pretty clear.
Don,
According to the "rules", you should call Release for every Copy, Alloc, and Retain. So why are you calling Release on stuff? Is this assuming it was created using Alloc, Copy, or Retain?
This brings up another question: Is it harmful to call Release on a reference to an object if it's already been released?
Since Apple reserves the _ prefix for itself, and since I prefer to make it more obvious when I am using the setter and when I am using the ivar, I have adopted the practive of using a prefix of i_ on my ivars, so for example:
#interface MyClass : NSObject {
NSString *i_myVar;
}
#property (nonatomic, retain) NSString *myVar;
#synthesize myVar = i_myVar;
i_myVar = [input retain];
self.myVar = anotherInput;
[i_myVar release]
Since it is quite important to know when you are using the setter and when you are using the ivar, I find the explicitly different name is safer.
In your question, it should be:
self.myVar = #"Foo"; // with setter, equivalent to [self setMyVar:#"Foo"]
and
_myVar = some_other_object; // direct ivar access - no memory management!
Remember that you should not use setters/getters in init/dealloc, so you need to do your direct ivar access (and careful memory management) iin those methods.
what's wrong with simply using
#interface MyClass : NSObject
#property NSString *prop;
#end
nonatomic and retain are not required, retain is the default, and atomic/nonatomic isn\t important unless XCode tells you with a warning.
it is NOT necessary to declare the iVar, one will be created for you named _prop, if you really want to use one (i don't see why to be honest)
#synthesize is NOT required.
when (and you should) using ARC you don't have to bother with retain and release either.
keep it simple !
furthermore, if you have a method like this one
- (void)aMethod:(NSString*)string
{
self.prop = string;
// shows very clearly that we are setting the property of our object
_aName = string;
// what is _aName ? the _ is a convention, not a real visual help
}
i would always use properties, more flexible, easier to read.