1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "base/ios/crb_protocol_observers.h"
7 #include <objc/runtime.h>
11 #include "base/logging.h"
12 #include "base/mac/scoped_nsobject.h"
14 @interface CRBProtocolObservers () {
15 base::scoped_nsobject<Protocol> _protocol;
16 // ivars declared here are private to the implementation but must be
17 // public for allowing the C++ |Iterator| class access to those ivars.
19 // vector of weak pointers to observers.
20 std::vector<__unsafe_unretained id> _observers;
21 // The nested level of observer iteration.
22 // A depth of 0 means nobody is currently iterating on the list of observers.
26 // Removes nil observers from the list and is called when the
27 // |_invocationDepth| reaches 0.
36 explicit Iterator(CRBProtocolObservers* protocol_observers);
41 CRBProtocolObservers* protocol_observers_;
46 Iterator::Iterator(CRBProtocolObservers* protocol_observers)
47 : protocol_observers_(protocol_observers),
49 max_index_(protocol_observers->_observers.size()) {
50 DCHECK(protocol_observers_);
51 ++protocol_observers->_invocationDepth;
54 Iterator::~Iterator() {
55 if (protocol_observers_ && --protocol_observers_->_invocationDepth == 0)
56 [protocol_observers_ compact];
59 id Iterator::GetNext() {
60 if (!protocol_observers_)
62 auto& observers = protocol_observers_->_observers;
64 size_t max_index = std::min(max_index_, observers.size());
65 while (index_ < max_index && !observers[index_])
67 return index_ < max_index ? observers[index_++] : nil;
71 @interface CRBProtocolObservers ()
73 // Designated initializer.
74 - (id)initWithProtocol:(Protocol*)protocol;
78 @implementation CRBProtocolObservers
80 + (instancetype)observersWithProtocol:(Protocol*)protocol {
81 return [[[self alloc] initWithProtocol:protocol] autorelease];
89 - (id)initWithProtocol:(Protocol*)protocol {
92 _protocol.reset([protocol retain]);
97 - (Protocol*)protocol {
98 return _protocol.get();
101 - (void)addObserver:(id)observer {
103 DCHECK([observer conformsToProtocol:self.protocol]);
105 if (std::find(_observers.begin(), _observers.end(), observer) !=
109 _observers.push_back(observer);
112 - (void)removeObserver:(id)observer {
114 auto it = std::find(_observers.begin(), _observers.end(), observer);
115 if (it != _observers.end()) {
116 if (_invocationDepth)
119 _observers.erase(it);
125 for (id observer : _observers) {
132 #pragma mark - NSObject
134 - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
135 NSMethodSignature* signature = [super methodSignatureForSelector:selector];
139 // Look for a required method in the protocol. protocol_getMethodDescription
140 // returns a struct whose fields are null if a method for the selector was
142 struct objc_method_description description =
143 protocol_getMethodDescription(self.protocol, selector, YES, YES);
144 if (description.types)
145 return [NSMethodSignature signatureWithObjCTypes:description.types];
147 // Look for an optional method in the protocol.
148 description = protocol_getMethodDescription(self.protocol, selector, NO, YES);
149 if (description.types)
150 return [NSMethodSignature signatureWithObjCTypes:description.types];
152 // There is neither a required nor optional method with this selector in the
153 // protocol, so invoke -[NSObject doesNotRecognizeSelector:] to raise
154 // NSInvalidArgumentException.
155 [self doesNotRecognizeSelector:selector];
159 - (void)forwardInvocation:(NSInvocation*)invocation {
161 if (_observers.empty())
163 SEL selector = [invocation selector];
166 while ((observer = it.GetNext()) != nil) {
167 if ([observer respondsToSelector:selector])
168 [invocation invokeWithTarget:observer];
172 - (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
174 if (_observers.empty())
178 while ((observer = it.GetNext()) != nil)
182 #pragma mark - Private
185 DCHECK(!_invocationDepth);
186 _observers.erase(std::remove(_observers.begin(), _observers.end(), nil),