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
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]
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With