// 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 #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 _name; // A block of code to execute. base::scoped_nsprotocol _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 _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 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