External/Global Variables in Objective-C

Discussion in 'iOS Programming' started by RobRiley, Mar 24, 2011.

  1. RobRiley macrumors member

    Joined:
    Feb 4, 2009
    Location:
    London
    #1
    Hi,

    This is probably a bit of a noob question but here goes.

    My app has some constant/global variables that are set from the off and some that require setting during an authentication process such as a token. I'm having trouble with the getting/setting of external variables and it's possible I'm going about this completely the wrong way. I've re-created my code in a really simple example app to demonstrate:

    constants.h

    Code:
    #import <Foundation/Foundation.h>
    
    extern NSString *myConstString;
    extern NSString *const anotherConstString;
    
    @interface constants : NSObject {
    
    }
    
    +(void)setString:(NSString*)withString;
    
    +(NSString*)getString;
    
    @end
    constants.m

    Code:
    #import "constants.h"
    
    @implementation constants
    
    NSString *const anotherConstString = @"12345678";
    
    +(void)setString:(NSString*)withString{
    	NSString *myConstString = [[NSString alloc] initWithString:withString];
    }
    
    +(NSString*)getString{
    	NSString *myConstString2 = [[NSString alloc] init];
    	return myConstString2;
    }
    
    @end
    View Controller Implementation:

    Code:
    #import "stringTestViewController.h"
    #import "constants.h"
    
    @implementation stringTestViewController
    
    -(IBAction)stringTest{
    	[constants setString:@"1234"];
    	NSString *returnedString = [constants getString];
    	NSLog(@"The string is %@", returnedString);
    }
    So I *think* the string should be outputted to NSLog and also available to any other methods in the app, but it isn't. I'm pretty sure my initialisation of the string in the getter is wrong, but I'm not sure what to do about it.

    Help anyone?

    Many thanks,
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    I'd recommend using a more OO solution than externed variables. My personal choice would be to make a singleton object that holds these values. Another option is to add them to an existing singleton, say your application delegate object.
     
  3. RobRiley thread starter macrumors member

    Joined:
    Feb 4, 2009
    Location:
    London
    #3
    Thanks. I read a bit about that. Back to the drawing board then. Out of interest, can you see why my code isn't working?

    Thanks,
     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    I don't use extern variables but I'd say that you are shadowing the declarations of the extern variables with local variables inside the methods. Where you have NSString *myConstString = you are creating a variable with local scope within that method call only.
     
  5. firewood, Mar 24, 2011
    Last edited: Mar 24, 2011

    firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #5
    Global variable are fine to use, but also very dangerous if you don't know what you're doing.

    Your:

    Code:
    NSString *const anotherConstString = @"12345678";
    
    attempts to do a static object alloc outside of any method. Objective C doesn't support this. You have to do this assignment inside some init method.

    It should be:

    Code:
    NSString *anotherConstString = nil;
    
    and in some init method

    Code:
    - (...) {
    ...
     anotherConstString = @"12345678";
    ...
    }
    
    If you assign another object to this global, you had better be an expert in retain/release memory management.

    ADDED: you can actually code class getters and setters for global variables to more cleanly manage object memory.
     
  6. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #6
    @firewood, not correct. Constant external NSStrings like that work fine. You can do the same thing in C with a const char *.

    What's illegal is calling a function to initialize an external variable like that. That results in an initializer is not constant error.

    Code:
    NSString *const anotherConstString = @"12345678"; //legal
    const char * s = "whatever"; // legal
    const char * s1 = somefunction(); // illegal
     
  7. seepel macrumors 6502

    seepel

    Joined:
    Dec 22, 2009
    #7

    This is your problem. You're creating a local variable that hides your global string myConstString. If you really wanted to do it you should simply have this.

    Code:
    [myConstString release];
    myConstString = [[NSString alloc] initWithString:withString];
    
    But I think global variables like this should definitely be constant and unchanged like you did with anotherConstString. You see the problem yes? Your variable name implies that it will be constant, but then you change it! 10 to 1 if you go back to this code in a few months, you will be scratching your head as to why a variable called myConstString would change.

    I typically use this method for defining preferences keys to avoid typos as I set and read them.

    PrefrencesConstants.h
    Code:
    extern NSString const *PreferencesConstantSomeBoolConstant;
    extern NSString const *PreferencesConstantSomeOtherConstant;
    
    PreferencesConstants.m
    Code:
    NSString const *PreferencesConstantSomeBoolConstant = @"PreferencesConstantSomeBoolConstant";
    NSString const *PreferencesConstantSomeOtherConstant = @"PreferencesConstantSomeOtherConstant";
    
    So I can then do something like
    Code:
    #include "PreferencesConstants.h"
    
    [[NSUserDefaults standardDefaults] boolForKey:PreferencesConstantSomeBoolConstant];
    
    The key here is that these variables are never changed. As soon as you start changing global variables like this it will become hard to determine what is going on where, and it will be very easy to mess up. Do yourself a favor and if the data has any chance at all of changing, put it in a class as a member variable (hopefully a class that makes sense to own the data).
     
  8. RobRiley thread starter macrumors member

    Joined:
    Feb 4, 2009
    Location:
    London
    #8
    Thanks everyone. Yes that makes a little more sense now..

    So basically I have a method in my view controller that needs to set a variable during an authentication process that remains for the lifecycle of the app and is available to all other methods in all classes. What is the recommended way to do this? Can anyone give me a simple code example?

    Thanks again.
     
  9. seepel macrumors 6502

    seepel

    Joined:
    Dec 22, 2009
    #9
    I would store it as a member of the AppDelegate, that's always easy to get to...

    Code:
    [(MyAppDelegate*)[[UIApplication sharedApplication] delegate] setVariable:variable];
    SomeClass *class = [(MyAppDelegate*)[[UIApplication sharedApplication] delegate] variable];
    
    If you want it to be persistent across app launches you can look at NSUserDefaults, or the Keychain if it is sensitive data.
     
  10. RobRiley thread starter macrumors member

    Joined:
    Feb 4, 2009
    Location:
    London
    #10
    Thanks - that looks very useful :)
     

Share This Page