Question

All I want to do is make a utility class for my (stream capture) app that grabs settings from my website. I want to call it from other files as a simple [RemoteConfig updateSettings];

My goal is to use this remote configuration utility without making an object for every situation where I grab remote settings.

The information around static/class variables and methods in Objective C is hazy and very opinionated, so after a lot of experimenting, I got this to work. But it looks funny, which makes me think something is incorrect.

RemoteConfig.h simply declares the +(void) updateSettings method.

This is my RemoteConfig.m:

#import "RemoteConfig.h"

static NSMutableData* _configData;
static NSString* url = @"http://local.namehidden.com:90/json.html";
static int try;

@implementation RemoteConfig

+(void) updateSettings
{
    NSString *identifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];

    //Create URL request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
                                                           cachePolicy: NSURLRequestReloadIgnoringCacheData
                                                       timeoutInterval: 10];

    [request setHTTPMethod: @"POST"];
    NSString *post = [NSString stringWithFormat:@"id=%@", identifier];
    NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:postData];

    NSURLConnection* connection = [NSURLConnection connectionWithRequest:request
                                                                delegate:self];
    [connection start];
}

///////////////////////////// DELEGATE METHODS ///////////////////////////////////

+(void)connection:(NSConnection*)conn didReceiveResponse:(NSURLResponse*)response
{
       if (_configData == NULL) {
        _configData = [[NSMutableData alloc] init];
    }
    [_configData setLength:0];
    NSLog(@"didReceiveResponse: responseData length:(%d)", _configData.length);
}

/// and so on...

It looks funky, putting C-style variables above the @interface/@implementation. A lot of people say try to use properties, some say do the static method singleton trick, I've seen a little library that handles singletons but this was the simplest solution I found.

My questions-

  • Is this proverbially bad?
  • What limitations does this have?
  • What are the alternatives, and what is best?
Was it helpful?

Solution

Is this proverbially bad? What limitations does this have?

Global variables tend to impose a certain set of restrictions:

  • they often don't clean up their resources properly
  • are not thread safe (e.g. can be used from one thread or may introduce state per thread)
  • they may not necessarily be safe to nest
  • they can combat some of these problems by serializing requests -- introducing excessive suspension and locking.
  • they become very difficult to 'extend' safely (i.e. adding global variables makes it more fragile)
  • they are hard to test, and can lead to bugs which are very difficult to reproduce

What are the alternatives, and what is best?

Just move those variables to ivars, and create instances of the class rather than relying on global state. Then you can extend and abstract in a way which will not affect your clients significantly.

Note that static NSString* const url = @"http://local.namehidden.com:90/json.html"; would not be a mutable variable (added const). So it's only _configData and try which would need to be ivars.

OTHER TIPS

Using static variables like this is no less safe than using a Singleton. You will still have the same issues with thread safety e.g. A Singleton is of course easier to Mock so that might be a benefit with Singleton's.

In both cases you are introducing global mutable state (global immutable state is unproblematic). How problematic this is depends on where in the call hierarchy these variables exist. If most of your code is built on top of some functions which change their output based on some global mutable state then that makes it hard to test and analyse your code.

So if you do introduce global mutable state, try to either:

  1. Place it has high as possible in your layering. Meaning as little as possible other code should depend on this code.

  2. Make sure state changes don't change the output of functions using it. E.g. global mutable state which is just caching might work.

  3. If total code of your program is small you could use global state as there is little difference between global variables in a 500 line program and member variables in a 500 line class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top