| Index: base/ios/crb_protocol_observers.mm
|
| diff --git a/base/ios/crb_protocol_observers.mm b/base/ios/crb_protocol_observers.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ee9e23fcb4e255c29ff0a33590027a25360d9d0e
|
| --- /dev/null
|
| +++ b/base/ios/crb_protocol_observers.mm
|
| @@ -0,0 +1,99 @@
|
| +// Copyright 2014 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 "base/ios/crb_protocol_observers.h"
|
| +
|
| +#include <objc/runtime.h>
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/mac/scoped_nsobject.h"
|
| +
|
| +@interface CRBProtocolObservers ()
|
| +
|
| +// Designated initializer.
|
| +- (id)initWithProtocol:(Protocol*)protocol;
|
| +
|
| +@end
|
| +
|
| +@implementation CRBProtocolObservers {
|
| + base::scoped_nsobject<Protocol> _protocol;
|
| + base::scoped_nsobject<NSHashTable> _observers;
|
| +}
|
| +
|
| ++ (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol {
|
| + return [[[self alloc] initWithProtocol:protocol] autorelease];
|
| +}
|
| +
|
| +- (id)init {
|
| + NOTREACHED();
|
| + return nil;
|
| +}
|
| +
|
| +- (id)initWithProtocol:(Protocol*)protocol {
|
| + self = [super init];
|
| + if (self) {
|
| + _protocol.reset([protocol retain]);
|
| + _observers.reset([[NSHashTable weakObjectsHashTable] retain]);
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (Protocol*)protocol {
|
| + return _protocol.get();
|
| +}
|
| +
|
| +- (void)addObserver:(id)observer {
|
| + DCHECK([observer conformsToProtocol:self.protocol]);
|
| + [_observers addObject:observer];
|
| +}
|
| +
|
| +- (void)removeObserver:(id)observer {
|
| + [_observers removeObject:observer];
|
| +}
|
| +
|
| +#pragma mark - NSObject
|
| +
|
| +- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
|
| + NSMethodSignature* signature = [super methodSignatureForSelector:selector];
|
| + if (signature)
|
| + return signature;
|
| +
|
| + // Look for a required method in the protocol. protocol_getMethodDescription
|
| + // returns a struct whose fields are null if a method for the selector was
|
| + // not found.
|
| + struct objc_method_description description =
|
| + protocol_getMethodDescription(self.protocol, selector, YES, YES);
|
| + if (description.types)
|
| + return [NSMethodSignature signatureWithObjCTypes:description.types];
|
| +
|
| + // Look for an optional method in the protocol.
|
| + description = protocol_getMethodDescription(self.protocol, selector, NO, YES);
|
| + if (description.types)
|
| + return [NSMethodSignature signatureWithObjCTypes:description.types];
|
| +
|
| + // There is neither a required nor optional method with this selector in the
|
| + // protocol, so invoke -[NSObject doesNotRecognizeSelector:] to raise
|
| + // NSInvalidArgumentException.
|
| + [self doesNotRecognizeSelector:selector];
|
| + return nil;
|
| +}
|
| +
|
| +- (void)forwardInvocation:(NSInvocation*)invocation {
|
| + SEL selector = [invocation selector];
|
| + base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
|
| + for (id observer in observers.get()) {
|
| + if ([observer respondsToSelector:selector])
|
| + [invocation invokeWithTarget:observer];
|
| + }
|
| +}
|
| +
|
| +- (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
|
| + DCHECK(callback);
|
| + base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
|
| + for (id observer in observers.get()) {
|
| + callback(observer);
|
| + }
|
| +}
|
| +
|
| +@end
|
|
|