kvo是成对出现的,如果添加了监听,就要到必要的时候移除监听,如果重复移除监听就会导致闪退问题,解决方法也很简单,通过一个对象来管理kvo的添加和移除,添加了kvo就保存起来,移除的时候先拿到添加的列表,移除已经添加的,如果已经移除过,则return防止重复移除导致闪退,具体代码如下:
@interface KVOProxy : NSObject
/// 添加观察者
/// - Parameters:
/// - target: target
/// - observer: observer
/// - keypath: keypath
/// - options: options
/// - context: context
-(void)px_addObserverWithTarget:(NSObject *)target
observer:(NSObject *)observer
keypath:(NSString *)keypath
options:(NSKeyValueObservingOptions)options
context:(nullable void *)context;
/// 移除观察者
/// - Parameters:
/// - target: target
/// - observer: observer
/// - keypath: keypath
-(void)px_removeObserverWithTarget:(NSObject *)target
observer:(NSObject *)observer
keypath:(NSString *)keypath;
@end
#import "KVOProxy.h"
@interface KVOObject :NSObject
@property (nonatomic,copy) NSString *keypath;
@property (nonatomic,strong) NSObject *observer;
@property (nonatomic,strong) NSObject *target;
@end
@implementation KVOObject
-(instancetype)initWithTarget:(NSObject *)target keypath:(NSString *)keypath observer:(NSObject *)observer{
if(self = [super init]){
self.keypath = keypath;
self.target = target;
self.observer = observer;
}
return self;
}
@end
@interface KVOProxy ()
@property (nonatomic,strong) NSMutableArray<KVOObject *> *kvoInfo;
@property (nonatomic,strong) NSLock *lock;
@end
@implementation KVOProxy
-(void)px_addObserverWithTarget:(NSObject *)target observer:(NSObject *)observer keypath:(NSString *)keypath options:(NSKeyValueObservingOptions)options context:(nullable void *)context{
if(keypath.length == 0) return;
/// 加锁
[self.lock lock];
//判断是否是同一个target添加重复的keypath,已存在相同的记录就直接返回,不作处理
for (KVOObject *obj in self.kvoInfo) {
if([target isEqual:obj.target] && [keypath isEqualToString:obj.keypath]){
[self.lock unlock];
return;
}
}
/// 保存当前的kvo信息
[self.kvoInfo addObject:[[KVOObject alloc] initWithTarget:target keypath:keypath observer:observer]];
/// 添加监听
[target addObserver:observer forKeyPath:keypath options:options context:context];
[self.lock unlock];
}
-(void)px_removeObserverWithTarget:(NSObject *)target observer:(NSObject *)observer keypath:(NSString *)keypath{
if(keypath.length == 0) return;
[self.lock lock];
KVOObject *kvoObj;
for (KVOObject *obj in self.kvoInfo) {
if(([target isEqual:obj.target] && [keypath isEqualToString:obj.keypath])){
kvoObj = obj;
}
}
/// 如果没有找到直接return
if(!kvoObj){
[self.lock unlock];
return;
}
[self.kvoInfo removeObject:kvoObj];
/// 移除监听
[target removeObserver:observer forKeyPath:keypath];
[self.lock unlock];
}
#pragma mark - Lazy
-(NSMutableArray<KVOObject *> *)kvoInfo{
if(!_kvoInfo){
_kvoInfo = [NSMutableArray array];
}
return _kvoInfo;
}
-(NSLock *)lock{
if(!_lock){
_lock = [[NSLock alloc] init];
}
return _lock;
}
@end
具体使用:
@property (nonatomic,strong) KVOProxy *kvoProxy;
AVCaptureDevice * camDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
[self.kvoProxy px_addObserverWithTarget:camDevice observer:self keypath:@"adjustingFocus" options:NSKeyValueObservingOptionNew context:nil];
[self.kvoProxy px_removeObserverWithTarget:camDevice observer:self keypath:@"adjustingFocus"];