Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialising static variable in Objective-C

In an Objective-C class, I want to load just once the contents of a text file into an NSString so that it can be used by all instances of that class.

In the Java world, I learnt over the years that it is easy to get this subtly wrong in terms of thread safety if you don't use a proven idiom. So I'd like to make sure I use the correct idiom.

Can you show me an example of an Objective-C class that does this?

Here's my empty class that I'm starting with...

@interface TestClass : NSObject
- (NSString *)doSomething:(NSUInteger)aParam;
@end

@implementation TestClass {
}

- (id)init {
    self = [super init];
    if (self) {

    }
    return self;
}

- (NSString *)doSomething:(NSUInteger)aParam {
     // something with shared NSString loaded from text file, 
     //  depending on the value of aParam
     return @""; 
}
@end
like image 390
Steve McLeod Avatar asked Feb 19 '23 08:02

Steve McLeod


2 Answers

An idiomatic way of dealing with static properties in Objective C is hiding them behind class methods (the ones with +). Declare your string as a static inside the implementation of your class method, and use dispatch_once for initialization:

+ (id)stringFromFile {
    static dispatch_once_t once;
    static NSString *sharedString;
    dispatch_once(&once, ^{
        sharedString = [NSString
            stringWithContentsOfFile:@"MyFile"
            encoding:... // ...supply proper parameters here...
            error:...];
    });
    return sharedString;
}

This way of setting up static objects is thread-safe. The sharedString will be initialized once, even if the method is called concurrently from several threads.

Now you can get to your string from anywhere by calling [MyClass stringFromFile].

like image 88
Sergey Kalinichenko Avatar answered Feb 23 '23 14:02

Sergey Kalinichenko


Create an instance variable for your class instances to access, and a static variable inside your designated initialiser. Your designated initialiser should create the string object once (keeping it in the static variable) and assign it to the instance variable every time. For instance:

@implementation TestClass {
    NSString *_myString;
}

- (id)init {
    self = [super init];
    if (self == nil) return nil;

    static dispatch_once_t once;
    static NSString *aString = nil;
    dispatch_once(&once, ^{
        aString = ... // However you want to instantiate the string
    });
    _myString = aString;

    return self;
}

This lets you access the string in your instance methods as if it were a normal instance variable, despite the fact the string is created only once and each instance is pointing to the single object.

like image 31
Jim Avatar answered Feb 23 '23 12:02

Jim