Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(586)

Unified Diff: base/ios/crb_protocol_observers.mm

Issue 1157863009: CRBProtocolObservers can now be mutated while forwarding methods. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/ios/crb_protocol_observers.h ('k') | base/ios/crb_protocol_observers_unittest.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/ios/crb_protocol_observers.mm
diff --git a/base/ios/crb_protocol_observers.mm b/base/ios/crb_protocol_observers.mm
index ee9e23fcb4e255c29ff0a33590027a25360d9d0e..e69e43a85ef3d6776b38116627213b1be27f18ee 100644
--- a/base/ios/crb_protocol_observers.mm
+++ b/base/ios/crb_protocol_observers.mm
@@ -5,10 +5,68 @@
#import "base/ios/crb_protocol_observers.h"
#include <objc/runtime.h>
+#include <vector>
#include "base/logging.h"
#include "base/mac/scoped_nsobject.h"
+@interface CRBProtocolObservers () {
+ base::scoped_nsobject<Protocol> _protocol;
+ // ivar 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<__unsafe_unretained id> _observers;
+ // Indicate the nested level of observer iteration.
+ // A depth of 0 means nobody is currently iterating on the list of observers.
+ int _invocation_depth;
droger 2015/06/04 12:29:53 _invocationDepth
jbbegue 2015/06/04 12:41:45 Done.
+}
+
+// The methods will remove nil observers from the list and will be called when
droger 2015/06/04 12:29:53 s/will remove/removes/ s/will be/is/
jbbegue 2015/06/04 12:41:46 Done.
+// the |_invocation_depth| 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->_invocation_depth;
+}
+
+Iterator::~Iterator() {
+ if (protocol_observers_ && --protocol_observers_->_invocation_depth == 0)
+ [protocol_observers_ compact];
+}
+
+id Iterator::GetNext() {
+ if (!protocol_observers_)
+ return nil;
+ auto& observers = protocol_observers_->_observers;
+ // Skip null 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.
@@ -16,12 +74,9 @@
@end
-@implementation CRBProtocolObservers {
- base::scoped_nsobject<Protocol> _protocol;
- base::scoped_nsobject<NSHashTable> _observers;
-}
+@implementation CRBProtocolObservers
-+ (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol {
++ (instancetype)observersWithProtocol:(Protocol*)protocol {
return [[[self alloc] initWithProtocol:protocol] autorelease];
}
@@ -34,7 +89,6 @@
self = [super init];
if (self) {
_protocol.reset([protocol retain]);
- _observers.reset([[NSHashTable weakObjectsHashTable] retain]);
}
return self;
}
@@ -44,12 +98,29 @@
}
- (void)addObserver:(id)observer {
+ DCHECK(observer);
DCHECK([observer conformsToProtocol:self.protocol]);
- [_observers addObject:observer];
+
+ if (std::find(_observers.begin(), _observers.end(), observer) !=
+ _observers.end())
+ return;
+
+ _observers.push_back(observer);
}
- (void)removeObserver:(id)observer {
- [_observers removeObject:observer];
+ DCHECK(observer);
+ auto it = std::find(_observers.begin(), _observers.end(), observer);
+ if (it != _observers.end()) {
+ if (_invocation_depth)
+ *it = nil;
+ else
+ _observers.erase(it);
+ }
+}
+
+- (BOOL)empty {
+ return _observers.empty();
}
#pragma mark - NSObject
@@ -80,9 +151,13 @@
}
- (void)forwardInvocation:(NSInvocation*)invocation {
+ DCHECK(invocation);
+ if (_observers.empty())
+ return;
SEL selector = [invocation selector];
- base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
- for (id observer in observers.get()) {
+ Iterator it(self);
+ id observer;
+ while ((observer = it.GetNext()) != nil) {
if ([observer respondsToSelector:selector])
[invocation invokeWithTarget:observer];
}
@@ -90,10 +165,19 @@
- (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
DCHECK(callback);
- base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
- for (id observer in observers.get()) {
+ if (_observers.empty())
+ return;
+ Iterator it(self);
+ id observer;
+ while ((observer = it.GetNext()) != nil)
callback(observer);
- }
+}
+
+#pragma mark - Private
+
+- (void)compact {
+ _observers.erase(std::remove(_observers.begin(), _observers.end(), nil),
sdefresne 2015/06/04 12:32:48 nit: DCHECK(!_invocation_depth);
jbbegue 2015/06/04 12:41:46 Done.
+ _observers.end());
}
@end
« no previous file with comments | « base/ios/crb_protocol_observers.h ('k') | base/ios/crb_protocol_observers_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698