ijk这个KVO管理器跟上篇思路差不多,但代码完善度可用性甩我几条街,故贴出来供大家参考,源码地址 ijkplayer
#import <Foundation/Foundation.h>
@interface IJKKVOController : NSObject
- (id)initWithTarget:(NSObject *)target;
- (void)safelyAddObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
context:(void *)context;
- (void)safelyRemoveObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath;
- (void)safelyRemoveAllObservers;
@end
#import "IJKKVOController.h"
@interface IJKKVOEntry : NSObject
@property(nonatomic, weak) NSObject *observer;
@property(nonatomic, strong) NSString *keyPath;
@end
@implementation IJKKVOEntry
@synthesize observer;
@synthesize keyPath;
@end
@implementation IJKKVOController {
__weak NSObject *_target;
NSMutableArray *_observerArray;
}
- (id)initWithTarget:(NSObject *)target
{
self = [super init];
if (self) {
_target = target;
_observerArray = [[NSMutableArray alloc] init];
}
return self;
}
- (void)safelyAddObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
context:(void *)context
{
NSObject *target = _target;
if (target == nil)
return;
BOOL removed = [self removeEntryOfObserver:observer forKeyPath:keyPath];
if (removed) {
// duplicated register
NSLog(@"duplicated observer");
}
@try {
[target addObserver:observer
forKeyPath:keyPath
options:options
context:context];
IJKKVOEntry *entry = [[IJKKVOEntry alloc] init];
entry.observer = observer;
entry.keyPath = keyPath;
[_observerArray addObject:entry];
} @catch (NSException *e) {
NSLog(@"IJKKVO: failed to add observer for %@\n", keyPath);
}
}
- (void)safelyRemoveObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
{
NSObject *target = _target;
if (target == nil)
return;
BOOL removed = [self removeEntryOfObserver:observer forKeyPath:keyPath];
if (removed) {
// duplicated register
NSLog(@"duplicated observer");
}
@try {
if (removed) {
[target removeObserver:observer
forKeyPath:keyPath];
}
} @catch (NSException *e) {
NSLog(@"IJKKVO: failed to remove observer for %@\n", keyPath);
}
}
- (void)safelyRemoveAllObservers
{
__block NSObject *target = _target;
if (target == nil)
return;
[_observerArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
IJKKVOEntry *entry = obj;
if (entry == nil)
return;
NSObject *observer = entry.observer;
if (observer == nil)
return;
@try {
[target removeObserver:observer
forKeyPath:entry.keyPath];
} @catch (NSException *e) {
NSLog(@"IJKKVO: failed to remove observer for %@\n", entry.keyPath);
}
}];
[_observerArray removeAllObjects];
}
- (BOOL)removeEntryOfObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
{
__block NSInteger foundIndex = -1;
[_observerArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
IJKKVOEntry *entry = (IJKKVOEntry *)obj;
if (entry.observer == observer &&
[entry.keyPath isEqualToString:keyPath]) {
foundIndex = idx;
*stop = YES;
}
}];
if (foundIndex >= 0) {
[_observerArray removeObjectAtIndex:foundIndex];
return YES;
}
return NO;
}
@end