devxoul / UITextView-Placeholder

A missing placeholder for UITextView
MIT License
1.48k stars 259 forks source link

【optimize】Use observer object replace textView itself #76

Closed leaflinfeng closed 4 years ago

leaflinfeng commented 4 years ago

Swizzling dealloc and implement kvo method in category is not safe. We can use another observer object and associate it on textView. It can unobserve when textView dealloc.

Some code

@interface UITextView ()
@property (nonatomic, strong) _UITextViewObserver *xx_observer;
@end 

@interface _UITextViewObserver ()
@property (nonatomic, weak) UITextView *textView;
@end

@implementation _UITextViewObserver
+ (NSArray *)observingKeys {
    return @[
        @"attributedText",
        @"bounds",
        @"font",
        @"frame",
        @"text",
        @"textAlignment",
        @"textContainerInset",
        @"textContainer.exclusionPaths"
    ];
}
+ (instancetype)observerWithTextView:(UITextView *)textView
{
    _UITextViewObserver *observer = [_UITextViewObserver new];
    [[NSNotificationCenter defaultCenter] addObserver:observer selector:@selector(update) name:UITextViewTextDidChangeNotification object:textView];
    for (NSString *key in [self.class observingKeys]) {
        [textView addObserver:observer forKeyPath:key options:NSKeyValueObservingOptionNew context:nil];
    }
    observer.textView = textView;
    return observer;
}

- (void)update
{
    [self.textView updatePlaceholderTextView];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    [self update];
}

- (void)dealloc
{
    for (NSString *key in [self.class observingKeys]) {
        [self.textView removeObserver:self forKeyPath:key];
    }
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end