Update: While this does work, the Apple documentation says that this behavior is undefined:
The predicate must point to a variable stored in global or static scope. The result of using a predicate with automatic or dynamic storage (including Objective-C instance variables) is undefined.
Update II: Using OSMemoryBarrier() makes this behavior fully defined.
Ben Stiglitz wrote in with a suggestion. Using OSMemoryBarrier()
in the initializer of your object makes sure that it is globally visible (i.e., from any thread) before any code that references it executes.
Original Post:
Every use of dispatch_once that I’ve seen across the web has been for setting up singletons by using a static token to make sure the initialization code only runs once per session of the app.
+ (instancetype) sharedInstance {
static dispatch_once_t onceToken;
static id sharedInstance;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
This is a great technique, but I’ve been looking for a way to use dispatch_once once per instance instead of once per class, but it’s no really clear how to adapt the singleton technique for a per-instance technique. I hacked around with a new project today and figured it out. It ends up being about as straightforward as you would expect.
@interface MyClass ()
@property (nonatomic, assign) dispatch_once_t onceToken;
@end
Declare a dispatch_once_t single use token in your class’s extension, and use that for running the code you only want to run once (such as initialization).
- (void) setupThing {
dispatch_once(&_onceToken, ^{
//set up thing
});
}
You can now call this method as many times as you want (per instance) from any thread, and it will only be run once.