//
// LCLicenceObserver.m
// LicenceCore - https://indie.miln.eu
//
// Copyright © Graham Miln. All rights reserved. https://miln.eu
//
// This package is subject to the terms of the Artistic License 2.0.
// If a copy of the Artistic-2.0 was not distributed with this file, you can
// obtain one at https://indie.miln.eu/licence
#import "LCLicenceObserver.h"
// KVO Content
static NSString* LCLicenceObserverKVOIsLicensedContext = @"LCLicenceObserverKVOIsLicensedContext";
static NSString* LCLicenceObserverKVOLicencesContext = @"LCLicenceObserverKVOLicencesContext";
static NSString* LCLicenceObserverKVOPendingContext = @"LCLicenceObserverKVOPendingContext";
@interface LCLicenceObserver ()
@property(strong) LCLicenceCore* core;
@property(weak) NSObject<LCLicenceObserverProtocol>* delegate;
- (void)isLicensedDidChange:(BOOL)isLicensed;
- (void)licencesDidChange:(LCLicence*)aLicence;
@end
@implementation LCLicenceObserver
+ (instancetype)observerWithCore:(LCLicenceCore*)aCore delegate:(NSObject<LCLicenceObserverProtocol>*)aDelegate {
return [(LCLicenceObserver*)[[self class] alloc] initWithCore:aCore delegate:aDelegate];
}
- (instancetype)initWithCore:(LCLicenceCore*)aCore delegate:(NSObject<LCLicenceObserverProtocol>*)aDelegate {
NSParameterAssert(aCore);
NSParameterAssert(aDelegate);
if ((self = [super init])) {
self.core = aCore;
self.delegate = aDelegate;
[self.core addObserver:self forKeyPath:LCLicenceCoreKeyIsLicensed options:0 context:(__bridge void * _Nullable)(LCLicenceObserverKVOIsLicensedContext)];
[self.core addObserver:self forKeyPath:LCLicenceCoreKeyLicences options:(NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:(__bridge void * _Nullable)(LCLicenceObserverKVOLicencesContext)];
}
return self;
}
- (void)dealloc {
[self.core removeObserver:self forKeyPath:LCLicenceCoreKeyLicences context:(__bridge void * _Nullable)(LCLicenceObserverKVOLicencesContext)];
[self.core removeObserver:self forKeyPath:LCLicenceCoreKeyIsLicensed context:(__bridge void * _Nullable)(LCLicenceObserverKVOIsLicensedContext)];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (context == (__bridge void * _Nullable)(LCLicenceObserverKVOIsLicensedContext)) {
NSNumber* value = [object valueForKeyPath:keyPath];
if ([value respondsToSelector:@selector(boolValue)]) {
[self isLicensedDidChange:[value boolValue]];
}
} else if (context == (__bridge void * _Nullable)(LCLicenceObserverKVOLicencesContext)) {
id old = change[NSKeyValueChangeOldKey];
if ([old isKindOfClass:NSArray.class]) {
NSArray<LCLicence*>* oldLicences = old;
[oldLicences enumerateObjectsUsingBlock:^(LCLicence* inLicence, NSUInteger __unused inIndex,BOOL* __unused outShouldStop) {
[inLicence removeObserver:self forKeyPath:LCLicenceKeyIsPending context:(__bridge void * _Nullable)(LCLicenceObserverKVOPendingContext)];
}];
}
id new = change[NSKeyValueChangeNewKey];
if ([new isKindOfClass:NSArray.class]) {
NSArray<LCLicence*>* newLicences = new;
[newLicences enumerateObjectsUsingBlock:^(LCLicence* inLicence, NSUInteger __unused inIndex,BOOL* __unused outShouldStop) {
[inLicence addObserver:self forKeyPath:LCLicenceKeyIsPending options:(NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew) context:(__bridge void * _Nullable)(LCLicenceObserverKVOPendingContext)];
}];
}
// TODO: diff old and new, then inform delegate only for new licences
[self licencesDidChange:nil];
} else if (context == (__bridge void * _Nullable)(LCLicenceObserverKVOPendingContext)) {
if ([object isKindOfClass:LCLicence.class]) {
[self licencesDidChange:object];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark -
- (void)isLicensedDidChange:(BOOL)isLicensed {
if ([self.delegate respondsToSelector:@selector(licenceObserver:licensed:)]) {
[self.delegate licenceObserver:self licensed:isLicensed];
}
}
- (void)licencesDidChange:(LCLicence*)aLicence {
if ([self.delegate respondsToSelector:@selector(licenceObserver:didChange:)]) {
[self.delegate licenceObserver:self didChange:aLicence];
}
}
@end
LCLicenceObserver.m
This file can be downloaded as part of milnlicence.tbz.