blob: 4f537ff20964701b433a873ef8775853e21d1676 [file] [log] [blame]
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/app/deferred_initialization_runner.h"
#include <stdint.h>
#include "base/logging.h"
#include "base/mac/scoped_nsobject.h"
// An object encapsulating the deferred execution of a block of initialization
// code.
@interface DeferredInitializationBlock : NSObject {
// A string to reference the initialization block.
base::scoped_nsobject<NSString> _name;
// A block of code to execute.
base::scoped_nsprotocol<ProceduralBlock> _runBlock;
}
// Designated initializer.
- (id)initWithName:(NSString*)name block:(ProceduralBlock)block;
// Dispatches the deferred execution the block after |delaySeconds|.
- (void)dispatch:(NSTimeInterval)delaySeconds;
// Executes the deferred block now.
- (void)runSynchronously;
// Cancels the block's execution.
- (void)cancel;
@end
@implementation DeferredInitializationBlock
// Overrides default designated initializer.
- (id)init {
NOTREACHED();
return nil;
}
- (id)initWithName:(NSString*)name block:(ProceduralBlock)block {
DCHECK(block);
self = [super init];
if (self) {
_name.reset([name copy]);
_runBlock.reset([block copy]);
}
return self;
}
- (void)dispatch:(NSTimeInterval)delaySeconds {
int64_t nanoseconds = delaySeconds * NSEC_PER_SEC;
DCHECK([NSThread isMainThread]);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, nanoseconds),
dispatch_get_main_queue(), ^() {
[self runSynchronously];
});
}
- (void)runSynchronously {
ProceduralBlock deferredBlock = _runBlock.get();
if (!deferredBlock)
return;
deferredBlock();
[[DeferredInitializationRunner sharedInstance] cancelBlockNamed:_name];
}
- (void)cancel {
_runBlock.reset();
}
@end
@implementation DeferredInitializationRunner {
base::scoped_nsobject<NSMutableDictionary> _runBlocks;
}
+ (DeferredInitializationRunner*)sharedInstance {
static DeferredInitializationRunner* instance =
[[DeferredInitializationRunner alloc] init];
return instance;
}
- (id)init {
self = [super init];
if (self)
_runBlocks.reset([[NSMutableDictionary dictionary] retain]);
return self;
}
- (void)runBlockNamed:(NSString*)name
after:(NSTimeInterval)delaySeconds
block:(ProceduralBlock)block {
DCHECK(name);
// Safety check in case this function is called with a nanosecond or
// microsecond parameter by mistake.
DCHECK(delaySeconds < 3600.0);
// Cancels the previously scheduled block, if there is one, so this
// |name| block will not be run more than once.
[[_runBlocks objectForKey:name] cancel];
base::scoped_nsobject<DeferredInitializationBlock> deferredBlock(
[[DeferredInitializationBlock alloc] initWithName:name block:block]);
[_runBlocks setObject:deferredBlock forKey:name];
[deferredBlock dispatch:delaySeconds];
}
- (void)runBlockIfNecessary:(NSString*)name {
[[_runBlocks objectForKey:name] runSynchronously];
}
- (void)cancelBlockNamed:(NSString*)name {
DCHECK(name);
[[_runBlocks objectForKey:name] cancel];
[_runBlocks removeObjectForKey:name];
}
- (NSUInteger)numberOfBlocksRemaining {
return [_runBlocks count];
}
@end