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

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
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..60fe5f9f48951eab147026caf6d5e9f2b79a7b8c 100644
--- a/base/ios/crb_protocol_observers.mm
+++ b/base/ios/crb_protocol_observers.mm
@@ -5,10 +5,60 @@
#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;
+ @public
+ std::vector<__weak id> _observers;
sdefresne 2015/06/04 10:45:34 According to https://developer.apple.com/library/i
jbbegue 2015/06/04 12:13:03 Done.
+ int _invocation_depth;
sdefresne 2015/06/04 10:18:34 _invocationDepth
jbbegue 2015/06/04 12:13:02 Done.
+}
+
+- (void)compact;
+
+@end
+
+namespace {
+
+class Iterator {
+ public:
+ explicit Iterator(CRBProtocolObservers* protocolObservers);
+ ~Iterator();
+ id GetNext();
+
+ private:
+ CRBProtocolObservers* protocolObservers_ = nullptr;
sdefresne 2015/06/04 10:18:34 protocol_observers_
jbbegue 2015/06/04 12:13:03 Done.
+ size_t index_ = 0;
+ size_t max_index_;
+};
+
+Iterator::Iterator(CRBProtocolObservers* protocolObservers)
+ : protocolObservers_(protocolObservers),
+ index_(0),
+ max_index_(protocolObservers->_observers.size()) {
+ ++protocolObservers->_invocation_depth;
+}
+
+Iterator::~Iterator() {
+ if (protocolObservers_ && --protocolObservers_->_invocation_depth == 0)
+ [protocolObservers_ compact];
+}
+
+id Iterator::GetNext() {
+ if (!protocolObservers_)
+ return nil;
+ auto& observers = protocolObservers_->_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_++] : nullptr;
sdefresne 2015/06/04 10:18:34 s/nullptr/nil/
jbbegue 2015/06/04 12:13:03 Done.
+}
+}
+
@interface CRBProtocolObservers ()
// Designated initializer.
@@ -16,12 +66,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 +81,6 @@
self = [super init];
if (self) {
_protocol.reset([protocol retain]);
- _observers.reset([[NSHashTable weakObjectsHashTable] retain]);
}
return self;
}
@@ -44,12 +90,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 = nullptr;
sdefresne 2015/06/04 10:18:34 s/nullptr/nil/
jbbegue 2015/06/04 12:13:03 Done.
+ else
+ _observers.erase(it);
+ }
+}
+
+- (BOOL)empty {
+ return _observers.empty();
}
#pragma mark - NSObject
@@ -80,9 +143,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()) != nullptr) {
sdefresne 2015/06/04 10:18:34 s/nullptr/ or even remove the test
jbbegue 2015/06/04 12:13:03 Done.
if ([observer respondsToSelector:selector])
[invocation invokeWithTarget:observer];
}
@@ -90,10 +157,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()) != nullptr)
sdefresne 2015/06/04 10:18:34 s/nullptr/ or even remove the test
jbbegue 2015/06/04 12:13:02 Done.
callback(observer);
- }
+}
+
+#pragma mark - Private
+
+- (void)compact {
+ _observers.erase(std::remove(_observers.begin(), _observers.end(), nullptr),
sdefresne 2015/06/04 10:18:34 s/nullptr/nil
jbbegue 2015/06/04 12:13:03 Done.
+ _observers.end());
}
@end

Powered by Google App Engine
This is Rietveld 408576698