Avner Barr Avner Barr - 6 months ago 16
Objective-C Question

Using dispatch_once_t per object and not per class

There are multiple sources calling a particular method, but I would like to ensure that it is called exactly once (per object)

I would like to use syntax like

// method called possibly from multiple places (threads)
-(void)finish
{

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self _finishOnce]; // should happen once per object
});
}
// should only happen once per object
-(void)_finishOnce{...}


Problem is the token is shared accross all instances of the same class - so not a good solution - is there a dispatch_once_t per object - if not what is the best way to ensure it is called once?

EDIT:

Here is a proposed solution I am thinking of - does it seem alright?

@interface MyClass;

@property (nonatomic,strong) dispatch_queue_t dispatchOnceSerialQueue; // a serial queue for ordering of query to a ivar

@property (nonatomic) BOOL didRunExactlyOnceToken;

@end

@implementation MyClass

-(void)runExactlyOnceMethod
{
__block BOOL didAlreadyRun = NO;
dispatch_sync(self.dispatchOnceSerialQueue, ^{
didAlreadyRun = _didRunExactlyOnceToken;
if (_didRunExactlyOnceToken == NO) {
_didRunExactlyOnceToken = YES;
}
});
if (didAlreadyRun == YES)
{
return;
}
// do some work once
}

CRD CRD
Answer

Avner, you're probably regretting you asked by now ;-)

Regarding your edit to the question, and taking into account other issues, you've more-or-less recreated the "old school" way of doing this, and maybe that is just what you should do (code typed in directly, expect typos):

@implemention RACDisposable
{
   BOOL ranExactlyOnceMethod;
}

- (id) init
{
   ...
   ranExactlyOnceMethod = NO;
   ...
}

- (void) runExactlyOnceMethod
{
   @synchronized(self)     // lock
   {
      if (!ranExactlyOnceMethod) // not run yet?
      {
          // do stuff once
          ranExactlyOnceMethod = YES;
      }
   }
}

There is a common optimization to this, but given the other discussion let's skip that.

Is this "cheap"? Well probably not, but all things are relative, its expense is probably not significant - but YMMV!

HTH