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

Side by Side Diff: ios/chrome/browser/ui/util/label_observer.mm

Issue 2828743002: LabelObserver is no longer retained by the label (Closed)
Patch Set: Address comments Created 3 years, 8 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
« no previous file with comments | « ios/chrome/browser/ui/util/label_observer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "ios/chrome/browser/ui/util/label_observer.h" 5 #import "ios/chrome/browser/ui/util/label_observer.h"
6 6
7 #import <objc/runtime.h> 7 #import <objc/runtime.h>
8 8
9 #import "base/ios/weak_nsobject.h" 9 #import "base/ios/weak_nsobject.h"
10 #import "base/mac/scoped_block.h" 10 #import "base/mac/scoped_block.h"
(...skipping 20 matching lines...) Expand all
31 base::scoped_nsobject<NSMutableArray> _styleActions; 31 base::scoped_nsobject<NSMutableArray> _styleActions;
32 base::scoped_nsobject<NSMutableArray> _layoutActions; 32 base::scoped_nsobject<NSMutableArray> _layoutActions;
33 base::scoped_nsobject<NSMutableArray> _textActions; 33 base::scoped_nsobject<NSMutableArray> _textActions;
34 } 34 }
35 35
36 // Whether or not observer actions are currently being executed. This is used 36 // Whether or not observer actions are currently being executed. This is used
37 // to prevent infinite loops caused by a LinkObserverAction updating a 37 // to prevent infinite loops caused by a LinkObserverAction updating a
38 // property on |_label|. 38 // property on |_label|.
39 @property(nonatomic, assign, getter=isRespondingToKVO) BOOL respondingToKVO; 39 @property(nonatomic, assign, getter=isRespondingToKVO) BOOL respondingToKVO;
40 40
41 // The number of times this observer has been asked to observe the label. When
42 // reaching zero, the label stops being observed.
43 @property(nonatomic, assign) NSInteger observingCount;
44
41 // Initializes a LabelObserver that observes |label|. 45 // Initializes a LabelObserver that observes |label|.
42 - (instancetype)initWithLabel:(UILabel*)label NS_DESIGNATED_INITIALIZER; 46 - (instancetype)initWithLabel:(UILabel*)label NS_DESIGNATED_INITIALIZER;
43 47
48 // Adds |self| as observer for the |_label|.
49 - (void)registerAsObserver;
50
51 // Removes |self| as observer for the |_label|.
52 - (void)removeObserver;
53
44 // Performs all LabelObserverActions in |actions|. 54 // Performs all LabelObserverActions in |actions|.
45 - (void)performActions:(NSArray*)actions; 55 - (void)performActions:(NSArray*)actions;
46 56
47 // Takes |_label|'s values for each key from |styleKeys| and uses them to 57 // Takes |_label|'s values for each key from |styleKeys| and uses them to
48 // construct a uniformly attributed value to use for |_label|'s attributedText. 58 // construct a uniformly attributed value to use for |_label|'s attributedText.
49 - (void)resetLabelAttributes; 59 - (void)resetLabelAttributes;
50 60
51 @end 61 @end
52 62
53 // Properties of UILabel that, when changed, will cause the label's attributed 63 // Properties of UILabel that, when changed, will cause the label's attributed
54 // text to change. 64 // text to change.
55 static NSSet* styleKeys; 65 static NSSet* styleKeys;
56 // Properties of UILabel that invalidate the layout of the label if they change. 66 // Properties of UILabel that invalidate the layout of the label if they change.
57 static NSSet* layoutKeys; 67 static NSSet* layoutKeys;
58 // Properties of UILabel that may invalidate the text of the label if they 68 // Properties of UILabel that may invalidate the text of the label if they
59 // change. 69 // change.
60 static NSSet* textKeys; 70 static NSSet* textKeys;
61 71
62 @implementation LabelObserver 72 @implementation LabelObserver
63 73
64 @synthesize respondingToKVO = _respondingToKVO; 74 @synthesize respondingToKVO = _respondingToKVO;
75 @synthesize observingCount = _observingCount;
65 76
66 + (void)initialize { 77 + (void)initialize {
67 if (self == [LabelObserver class]) { 78 if (self == [LabelObserver class]) {
68 styleKeys = [[NSSet alloc] initWithArray:@[ 79 styleKeys = [[NSSet alloc] initWithArray:@[
69 @"font", @"textColor", @"textAlignment", @"lineBreakMode", @"shadowColor", 80 @"font", @"textColor", @"textAlignment", @"lineBreakMode", @"shadowColor",
70 @"shadowOffset" 81 @"shadowOffset"
71 ]]; 82 ]];
72 layoutKeys = [[NSSet alloc] 83 layoutKeys = [[NSSet alloc]
73 initWithArray:@[ @"bounds", @"frame", @"superview", @"center" ]]; 84 initWithArray:@[ @"bounds", @"frame", @"superview", @"center" ]];
74 textKeys = [[NSSet alloc] initWithArray:@[ @"text", @"attributedText" ]]; 85 textKeys = [[NSSet alloc] initWithArray:@[ @"text", @"attributedText" ]];
75 } 86 }
76 } 87 }
77 88
78 - (instancetype)initWithLabel:(UILabel*)label { 89 - (instancetype)initWithLabel:(UILabel*)label {
79 if ((self = [super init])) { 90 if ((self = [super init])) {
80 DCHECK(label); 91 DCHECK(label);
81 _label.reset(label); 92 _label.reset(label);
82 for (NSSet* keySet in @[ styleKeys, layoutKeys, textKeys ]) {
83 for (NSString* key in keySet) {
84 [_label addObserver:self
85 forKeyPath:key
86 options:NSKeyValueObservingOptionNew
87 context:nullptr];
88 }
89 }
90 [self resetLabelAttributes]; 93 [self resetLabelAttributes];
91 } 94 }
92 return self; 95 return self;
93 } 96 }
94 97
95 - (void)dealloc {
96 for (NSSet* keySet in @[ styleKeys, layoutKeys, textKeys ]) {
97 for (NSString* key in keySet) {
98 [_label removeObserver:self forKeyPath:key];
99 }
100 }
101 [super dealloc];
102 }
103 98
104 #pragma mark - Public interface 99 #pragma mark - Public interface
105 100
106 + (instancetype)observerForLabel:(UILabel*)label { 101 + (instancetype)observerForLabel:(UILabel*)label {
107 if (!label) 102 if (!label)
108 return nil; 103 return nil;
109 id observer = objc_getAssociatedObject(label, kLabelObserverKey); 104 id observer = objc_getAssociatedObject(label, kLabelObserverKey);
110 if (!observer) { 105 if (!observer) {
111 observer = [[LabelObserver alloc] initWithLabel:label]; 106 observer = [[LabelObserver alloc] initWithLabel:label];
112 objc_setAssociatedObject(label, kLabelObserverKey, observer, 107 objc_setAssociatedObject(label, kLabelObserverKey, observer,
113 OBJC_ASSOCIATION_RETAIN_NONATOMIC); 108 OBJC_ASSOCIATION_ASSIGN);
114 [observer release]; 109 [observer autorelease];
115 } 110 }
116 return observer; 111 return observer;
117 } 112 }
118 113
114 - (void)startObserving {
115 if (self.observingCount++ == 0) {
stkhapugin 2017/04/19 16:39:40 Please don't put two operations - increment and co
pkl (ping after 24h if needed) 2017/04/19 16:48:03 Readability aside, do the two implementations do t
gambard 2017/04/20 08:30:18 No, the increment should be outside the if. Done.
116 [self registerAsObserver];
117 }
118 }
119
120 - (void)stopObserving {
121 if (self.observingCount == 0)
122 return;
123
124 if (self.observingCount-- == 1) {
125 [self removeObserver];
126 }
127 }
128
119 - (void)addStyleChangedAction:(LabelObserverAction)action { 129 - (void)addStyleChangedAction:(LabelObserverAction)action {
120 DCHECK(action); 130 DCHECK(action);
121 if (!_styleActions) 131 if (!_styleActions)
122 _styleActions.reset([[NSMutableArray alloc] init]); 132 _styleActions.reset([[NSMutableArray alloc] init]);
123 base::mac::ScopedBlock<LabelObserverAction> actionCopy([action copy]); 133 base::mac::ScopedBlock<LabelObserverAction> actionCopy([action copy]);
124 [_styleActions addObject:actionCopy]; 134 [_styleActions addObject:actionCopy];
125 } 135 }
126 136
127 - (void)addLayoutChangedAction:(LabelObserverAction)action { 137 - (void)addLayoutChangedAction:(LabelObserverAction)action {
128 DCHECK(action); 138 DCHECK(action);
129 if (!_layoutActions) 139 if (!_layoutActions)
130 _layoutActions.reset([[NSMutableArray alloc] init]); 140 _layoutActions.reset([[NSMutableArray alloc] init]);
131 base::mac::ScopedBlock<LabelObserverAction> actionCopy([action copy]); 141 base::mac::ScopedBlock<LabelObserverAction> actionCopy([action copy]);
132 [_layoutActions addObject:actionCopy]; 142 [_layoutActions addObject:actionCopy];
133 } 143 }
134 144
135 - (void)addTextChangedAction:(LabelObserverAction)action { 145 - (void)addTextChangedAction:(LabelObserverAction)action {
136 DCHECK(action); 146 DCHECK(action);
137 if (!_textActions) 147 if (!_textActions)
138 _textActions.reset([[NSMutableArray alloc] init]); 148 _textActions.reset([[NSMutableArray alloc] init]);
139 base::mac::ScopedBlock<LabelObserverAction> actionCopy([action copy]); 149 base::mac::ScopedBlock<LabelObserverAction> actionCopy([action copy]);
140 [_textActions addObject:actionCopy]; 150 [_textActions addObject:actionCopy];
141 } 151 }
142 152
143 #pragma mark - 153 #pragma mark -
144 154
155 - (void)registerAsObserver {
156 for (NSSet* keySet in @[ styleKeys, layoutKeys, textKeys ]) {
157 for (NSString* key in keySet) {
158 [_label addObserver:self
159 forKeyPath:key
160 options:NSKeyValueObservingOptionNew
161 context:nullptr];
162 }
163 }
164 }
165
166 - (void)removeObserver {
167 for (NSSet* keySet in @[ styleKeys, layoutKeys, textKeys ]) {
168 for (NSString* key in keySet) {
169 [_label removeObserver:self forKeyPath:key];
170 }
171 };
172 }
173
145 - (void)performActions:(NSArray*)actions { 174 - (void)performActions:(NSArray*)actions {
146 for (LabelObserverAction action in actions) 175 for (LabelObserverAction action in actions)
147 action(_label); 176 action(_label);
148 } 177 }
149 178
150 - (void)resetLabelAttributes { 179 - (void)resetLabelAttributes {
151 if ([_label attributedText] || ![_label text]) 180 if ([_label attributedText] || ![_label text])
152 return; 181 return;
153 NSMutableDictionary* labelStyle = 182 NSMutableDictionary* labelStyle =
154 [NSMutableDictionary dictionaryWithCapacity:styleKeys.count]; 183 [NSMutableDictionary dictionaryWithCapacity:styleKeys.count];
(...skipping 25 matching lines...) Expand all
180 [self resetLabelAttributes]; 209 [self resetLabelAttributes];
181 [self performActions:_textActions]; 210 [self performActions:_textActions];
182 } else { 211 } else {
183 NOTREACHED() << "Unexpected label key <" << base::SysNSStringToUTF8(key) 212 NOTREACHED() << "Unexpected label key <" << base::SysNSStringToUTF8(key)
184 << "> observed"; 213 << "> observed";
185 } 214 }
186 self.respondingToKVO = NO; 215 self.respondingToKVO = NO;
187 } 216 }
188 217
189 @end 218 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/util/label_observer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698