Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |