123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- // 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 <stddef.h>
- #include <algorithm>
- #include <vector>
- #include "base/check.h"
- #include "base/containers/contains.h"
- #include "base/notreached.h"
- #if !defined(__has_feature) || !__has_feature(objc_arc)
- #error "This file requires ARC support."
- #endif
- @interface CRBProtocolObservers () {
- Protocol* _protocol;
- // ivars declared here are private to the implementation but must be
- // public for allowing the C++ |Iterator| class access to those ivars.
- @public
- // vector of weak pointers to observers.
- std::vector<__weak id> _observers;
- // The nested level of observer iteration.
- // A depth of 0 means nobody is currently iterating on the list of observers.
- int _invocationDepth;
- }
- // Removes nil observers from the list and is called when the
- // |_invocationDepth| reaches 0.
- - (void)compact;
- @end
- namespace {
- class Iterator {
- public:
- explicit Iterator(CRBProtocolObservers* protocol_observers);
- ~Iterator();
- id GetNext();
- private:
- CRBProtocolObservers* protocol_observers_;
- size_t index_;
- size_t max_index_;
- };
- Iterator::Iterator(CRBProtocolObservers* protocol_observers)
- : protocol_observers_(protocol_observers),
- index_(0),
- max_index_(protocol_observers->_observers.size()) {
- DCHECK(protocol_observers_);
- ++protocol_observers->_invocationDepth;
- }
- Iterator::~Iterator() {
- if (protocol_observers_ && --protocol_observers_->_invocationDepth == 0)
- [protocol_observers_ compact];
- }
- id Iterator::GetNext() {
- if (!protocol_observers_)
- return nil;
- auto& observers = protocol_observers_->_observers;
- // Skip nil elements.
- size_t max_index = std::min(max_index_, observers.size());
- while (index_ < max_index && !observers[index_])
- ++index_;
- return index_ < max_index ? observers[index_++] : nil;
- }
- }
- @interface CRBProtocolObservers ()
- // Designated initializer.
- - (instancetype)initWithProtocol:(Protocol*)protocol;
- @end
- @implementation CRBProtocolObservers
- + (instancetype)observersWithProtocol:(Protocol*)protocol {
- return [[self alloc] initWithProtocol:protocol];
- }
- - (id)init {
- NOTREACHED();
- return nil;
- }
- - (id)initWithProtocol:(Protocol*)protocol {
- self = [super init];
- if (self) {
- _protocol = protocol;
- }
- return self;
- }
- - (Protocol*)protocol {
- return _protocol;
- }
- - (void)addObserver:(id)observer {
- DCHECK(observer);
- DCHECK([observer conformsToProtocol:self.protocol]);
- if (base::Contains(_observers, observer))
- return;
- _observers.push_back(observer);
- }
- - (void)removeObserver:(id)observer {
- DCHECK(observer);
- auto it = std::find(_observers.begin(), _observers.end(), observer);
- if (it != _observers.end()) {
- if (_invocationDepth)
- *it = nil;
- else
- _observers.erase(it);
- }
- }
- - (BOOL)empty {
- int count = 0;
- for (id observer : _observers) {
- if (observer != nil)
- ++count;
- }
- return count == 0;
- }
- #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 {
- DCHECK(invocation);
- if (_observers.empty())
- return;
- SEL selector = [invocation selector];
- Iterator it(self);
- id observer;
- while ((observer = it.GetNext()) != nil) {
- if ([observer respondsToSelector:selector])
- [invocation invokeWithTarget:observer];
- }
- }
- - (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
- DCHECK(callback);
- if (_observers.empty())
- return;
- Iterator it(self);
- id observer;
- while ((observer = it.GetNext()) != nil)
- callback(observer);
- }
- #pragma mark - Private
- - (void)compact {
- DCHECK(!_invocationDepth);
- _observers.erase(std::remove(_observers.begin(), _observers.end(), nil),
- _observers.end());
- }
- @end
|