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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "base/ios/crb_protocol_observers.h" 5 #import "base/ios/crb_protocol_observers.h"
6 6
7 #include <objc/runtime.h> 7 #include <objc/runtime.h>
8 #include <vector>
8 9
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/mac/scoped_nsobject.h" 11 #include "base/mac/scoped_nsobject.h"
11 12
13 @interface CRBProtocolObservers () {
14 base::scoped_nsobject<Protocol> _protocol;
15 @public
16 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.
17 int _invocation_depth;
sdefresne 2015/06/04 10:18:34 _invocationDepth
jbbegue 2015/06/04 12:13:02 Done.
18 }
19
20 - (void)compact;
21
22 @end
23
24 namespace {
25
26 class Iterator {
27 public:
28 explicit Iterator(CRBProtocolObservers* protocolObservers);
29 ~Iterator();
30 id GetNext();
31
32 private:
33 CRBProtocolObservers* protocolObservers_ = nullptr;
sdefresne 2015/06/04 10:18:34 protocol_observers_
jbbegue 2015/06/04 12:13:03 Done.
34 size_t index_ = 0;
35 size_t max_index_;
36 };
37
38 Iterator::Iterator(CRBProtocolObservers* protocolObservers)
39 : protocolObservers_(protocolObservers),
40 index_(0),
41 max_index_(protocolObservers->_observers.size()) {
42 ++protocolObservers->_invocation_depth;
43 }
44
45 Iterator::~Iterator() {
46 if (protocolObservers_ && --protocolObservers_->_invocation_depth == 0)
47 [protocolObservers_ compact];
48 }
49
50 id Iterator::GetNext() {
51 if (!protocolObservers_)
52 return nil;
53 auto& observers = protocolObservers_->_observers;
54 // Skip null elements.
55 size_t max_index = std::min(max_index_, observers.size());
56 while (index_ < max_index && !observers[index_])
57 ++index_;
58 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.
59 }
60 }
61
12 @interface CRBProtocolObservers () 62 @interface CRBProtocolObservers ()
13 63
14 // Designated initializer. 64 // Designated initializer.
15 - (id)initWithProtocol:(Protocol*)protocol; 65 - (id)initWithProtocol:(Protocol*)protocol;
16 66
17 @end 67 @end
18 68
19 @implementation CRBProtocolObservers { 69 @implementation CRBProtocolObservers
20 base::scoped_nsobject<Protocol> _protocol;
21 base::scoped_nsobject<NSHashTable> _observers;
22 }
23 70
24 + (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol { 71 + (instancetype)observersWithProtocol:(Protocol*)protocol {
25 return [[[self alloc] initWithProtocol:protocol] autorelease]; 72 return [[[self alloc] initWithProtocol:protocol] autorelease];
26 } 73 }
27 74
28 - (id)init { 75 - (id)init {
29 NOTREACHED(); 76 NOTREACHED();
30 return nil; 77 return nil;
31 } 78 }
32 79
33 - (id)initWithProtocol:(Protocol*)protocol { 80 - (id)initWithProtocol:(Protocol*)protocol {
34 self = [super init]; 81 self = [super init];
35 if (self) { 82 if (self) {
36 _protocol.reset([protocol retain]); 83 _protocol.reset([protocol retain]);
37 _observers.reset([[NSHashTable weakObjectsHashTable] retain]);
38 } 84 }
39 return self; 85 return self;
40 } 86 }
41 87
42 - (Protocol*)protocol { 88 - (Protocol*)protocol {
43 return _protocol.get(); 89 return _protocol.get();
44 } 90 }
45 91
46 - (void)addObserver:(id)observer { 92 - (void)addObserver:(id)observer {
93 DCHECK(observer);
47 DCHECK([observer conformsToProtocol:self.protocol]); 94 DCHECK([observer conformsToProtocol:self.protocol]);
48 [_observers addObject:observer]; 95
96 if (std::find(_observers.begin(), _observers.end(), observer) !=
97 _observers.end())
98 return;
99
100 _observers.push_back(observer);
49 } 101 }
50 102
51 - (void)removeObserver:(id)observer { 103 - (void)removeObserver:(id)observer {
52 [_observers removeObject:observer]; 104 DCHECK(observer);
105 auto it = std::find(_observers.begin(), _observers.end(), observer);
106 if (it != _observers.end()) {
107 if (_invocation_depth)
108 *it = nullptr;
sdefresne 2015/06/04 10:18:34 s/nullptr/nil/
jbbegue 2015/06/04 12:13:03 Done.
109 else
110 _observers.erase(it);
111 }
112 }
113
114 - (BOOL)empty {
115 return _observers.empty();
53 } 116 }
54 117
55 #pragma mark - NSObject 118 #pragma mark - NSObject
56 119
57 - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector { 120 - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
58 NSMethodSignature* signature = [super methodSignatureForSelector:selector]; 121 NSMethodSignature* signature = [super methodSignatureForSelector:selector];
59 if (signature) 122 if (signature)
60 return signature; 123 return signature;
61 124
62 // Look for a required method in the protocol. protocol_getMethodDescription 125 // Look for a required method in the protocol. protocol_getMethodDescription
(...skipping 10 matching lines...) Expand all
73 return [NSMethodSignature signatureWithObjCTypes:description.types]; 136 return [NSMethodSignature signatureWithObjCTypes:description.types];
74 137
75 // There is neither a required nor optional method with this selector in the 138 // There is neither a required nor optional method with this selector in the
76 // protocol, so invoke -[NSObject doesNotRecognizeSelector:] to raise 139 // protocol, so invoke -[NSObject doesNotRecognizeSelector:] to raise
77 // NSInvalidArgumentException. 140 // NSInvalidArgumentException.
78 [self doesNotRecognizeSelector:selector]; 141 [self doesNotRecognizeSelector:selector];
79 return nil; 142 return nil;
80 } 143 }
81 144
82 - (void)forwardInvocation:(NSInvocation*)invocation { 145 - (void)forwardInvocation:(NSInvocation*)invocation {
146 DCHECK(invocation);
147 if (_observers.empty())
148 return;
83 SEL selector = [invocation selector]; 149 SEL selector = [invocation selector];
84 base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]); 150 Iterator it(self);
85 for (id observer in observers.get()) { 151 id observer;
152 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.
86 if ([observer respondsToSelector:selector]) 153 if ([observer respondsToSelector:selector])
87 [invocation invokeWithTarget:observer]; 154 [invocation invokeWithTarget:observer];
88 } 155 }
89 } 156 }
90 157
91 - (void)executeOnObservers:(ExecutionWithObserverBlock)callback { 158 - (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
92 DCHECK(callback); 159 DCHECK(callback);
93 base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]); 160 if (_observers.empty())
94 for (id observer in observers.get()) { 161 return;
162 Iterator it(self);
163 id observer;
164 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.
95 callback(observer); 165 callback(observer);
96 } 166 }
167
168 #pragma mark - Private
169
170 - (void)compact {
171 _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.
172 _observers.end());
97 } 173 }
98 174
99 @end 175 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698