This commit is contained in:
giuseppenuc committed 2016-12-20 16:02:27 +01:00
1 parent 1bf4b9ef1d
commit 4e66c377fd
664 files changed
+14818 -10172

No files matched your search

@@ -49,8 +49,17 @@ static void* const kRZDBSwizzledDeallocKey = (void *)&kRZDBSwizzledDeallocKey;
static void* const kRZDBKVOContext = (void *)&kRZDBKVOContext;
static void* const kRZDBRegisteredObserversKey = (void *)&kRZDBRegisteredObserversKey;
static void* const kRZDBDependentObserversKey = (void *)&kRZDBDependentObserversKey;
#define RZDBNotNull(obj) ((obj) != nil && ![(obj) isEqual:[NSNull null]])
#define rz_registeredObservers(obj) objc_getAssociatedObject(obj, kRZDBRegisteredObserversKey)
#define rz_setRegisteredObservers(obj, observers) objc_setAssociatedObject(obj, kRZDBRegisteredObserversKey, observers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
#define rz_dependentObservers(obj) objc_getAssociatedObject(obj, kRZDBDependentObserversKey)
#define rz_setDependentObservers(obj, observers) objc_setAssociatedObject(obj, kRZDBDependentObserversKey, observers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
#pragma mark - RZDataBinding_Private interface
// methods used to implement RZDB_AUTOMATIC_CLEANUP
@@ -59,12 +68,6 @@ void rz_swizzleDeallocIfNeeded(Class class);
@interface NSObject (RZDataBinding_Private)
- (NSMutableArray *)rz_registeredObservers;
- (void)rz_setRegisteredObservers:(NSMutableArray *)registeredObservers;
- (RZDBObserverContainer *)rz_dependentObservers;
- (void)rz_setDependentObservers:(RZDBObserverContainer *)dependentObservers;
- (void)rz_addTarget:(id)target action:(SEL)action boundKey:(NSString *)boundKey bindingTransform:(RZDBKeyBindingTransform)bindingTransform forKeyPath:(NSString *)keyPath withOptions:(NSKeyValueObservingOptions)options;
- (void)rz_removeTarget:(id)target action:(SEL)action boundKey:(NSString *)boundKey forKeyPath:(NSString *)keyPath;
- (void)rz_observeBoundKeyChange:(NSDictionary *)change;
@@ -99,11 +102,14 @@ void rz_swizzleDeallocIfNeeded(Class class);
@interface RZDBObserverContainer : NSObject
@property (strong, nonatomic) NSHashTable *observers;
+ (instancetype)strongContainer;
+ (instancetype)weakContainer;
- (void)addObserver:(RZDBObserver *)observer;
- (void)removeObserver:(RZDBObserver *)observer;
- (void)enumerateObserversUsingBlock:(void (^)(RZDBObserver *observer, BOOL *stop))block;
@end
#pragma mark - RZDataBinding implementation
@@ -195,29 +201,9 @@ void rz_swizzleDeallocIfNeeded(Class class);
@implementation NSObject (RZDataBinding_Private)
- (NSMutableArray *)rz_registeredObservers
{
return objc_getAssociatedObject(self, @selector(rz_registeredObservers));
}
- (void)rz_setRegisteredObservers:(NSMutableArray *)registeredObservers
{
objc_setAssociatedObject(self, @selector(rz_registeredObservers), registeredObservers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (RZDBObserverContainer *)rz_dependentObservers
{
return objc_getAssociatedObject(self, @selector(rz_dependentObservers));
}
- (void)rz_setDependentObservers:(RZDBObserverContainer *)dependentObservers
{
objc_setAssociatedObject(self, @selector(rz_dependentObservers), dependentObservers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)rz_addTarget:(id)target action:(SEL)action boundKey:(NSString *)boundKey bindingTransform:(RZDBKeyBindingTransform)bindingTransform forKeyPath:(NSString *)keyPath withOptions:(NSKeyValueObservingOptions)options
{
NSMutableArray *registeredObservers = nil;
RZDBObserverContainer *registeredObservers = nil;
RZDBObserverContainer *dependentObservers = nil;
RZDBObserver *observer = [[RZDBObserver alloc] initWithObservedObject:self keyPath:keyPath observationOptions:options];
@@ -225,27 +211,27 @@ void rz_swizzleDeallocIfNeeded(Class class);
[observer setTarget:target action:action boundKey:boundKey bindingTransform:bindingTransform];
@synchronized (self) {
registeredObservers = [self rz_registeredObservers];
registeredObservers = rz_registeredObservers(self);
if ( registeredObservers == nil ) {
registeredObservers = [NSMutableArray array];
[self rz_setRegisteredObservers:registeredObservers];
registeredObservers = [RZDBObserverContainer strongContainer];
rz_setRegisteredObservers(self, registeredObservers);
}
[registeredObservers addObject:observer];
}
[registeredObservers addObserver:observer];
@synchronized (target) {
dependentObservers = [target rz_dependentObservers];
dependentObservers = rz_dependentObservers(target);
if ( dependentObservers == nil ) {
dependentObservers = [[RZDBObserverContainer alloc] init];
[target rz_setDependentObservers:dependentObservers];
dependentObservers = [RZDBObserverContainer weakContainer];
rz_setDependentObservers(target, dependentObservers);
}
[dependentObservers addObserver:observer];
}
[dependentObservers addObserver:observer];
#if RZDB_AUTOMATIC_CLEANUP
rz_swizzleDeallocIfNeeded([self class]);
rz_swizzleDeallocIfNeeded([target class]);
@@ -254,22 +240,18 @@ void rz_swizzleDeallocIfNeeded(Class class);
- (void)rz_removeTarget:(id)target action:(SEL)action boundKey:(NSString *)boundKey forKeyPath:(NSString *)keyPath
{
@synchronized (self) {
NSMutableArray *registeredObservers = [self rz_registeredObservers];
[rz_registeredObservers(self) enumerateObserversUsingBlock:^(RZDBObserver *observer, BOOL *stop) {
BOOL targetsEqual = (target == observer.target);
BOOL actionsEqual = (action == NULL || action == observer.action);
BOOL boundKeysEqual = (boundKey == observer.boundKey || [boundKey isEqualToString:observer.boundKey]);
BOOL keyPathsEqual = [keyPath isEqualToString:observer.keyPath];
[registeredObservers enumerateObjectsUsingBlock:^(RZDBObserver *observer, NSUInteger idx, BOOL *stop) {
BOOL targetsEqual = (target == observer.target);
BOOL actionsEqual = (action == NULL || action == observer.action);
BOOL boundKeysEqual = (boundKey == observer.boundKey || [boundKey isEqualToString:observer.boundKey]);
BOOL keyPathsEqual = [keyPath isEqualToString:observer.keyPath];
BOOL allEqual = (targetsEqual && actionsEqual && boundKeysEqual && keyPathsEqual);
BOOL allEqual = (targetsEqual && actionsEqual && boundKeysEqual && keyPathsEqual);
if ( allEqual ) {
[observer invalidate];
}
}];
}
if ( allEqual ) {
[observer invalidate];
}
}];
}
- (void)rz_observeBoundKeyChange:(NSDictionary *)change
@@ -298,14 +280,11 @@ void rz_swizzleDeallocIfNeeded(Class class);
- (void)rz_cleanupObservers
{
NSMutableArray *registeredObservers = [self rz_registeredObservers];
RZDBObserverContainer *dependentObservers = [self rz_dependentObservers];
[[registeredObservers copy] enumerateObjectsUsingBlock:^(RZDBObserver *obs, NSUInteger idx, BOOL *stop) {
[rz_registeredObservers(self) enumerateObserversUsingBlock:^(RZDBObserver *obs, BOOL *stop) {
[obs invalidate];
}];
[[dependentObservers.observers allObjects] enumerateObjectsUsingBlock:^(RZDBObserver *obs, NSUInteger idx, BOOL *stop) {
[rz_dependentObservers(self) enumerateObserversUsingBlock:^(RZDBObserver *obs, BOOL *stop) {
[obs invalidate];
}];
}
@@ -343,13 +322,24 @@ void rz_swizzleDeallocIfNeeded(Class class);
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ( context == kRZDBKVOContext ) {
if ( self.methodSignature.numberOfArguments > 2 ) {
NSDictionary *changeDict = [self changeDictForKVOChange:change];
id target = nil;
SEL action = NULL;
NSDictionary *changeDict = nil;
((void(*)(id, SEL, NSDictionary *))objc_msgSend)(self.target, self.action, changeDict);
@synchronized (self) {
target = self.target;
action = self.action;
if ( self.methodSignature.numberOfArguments > 2 ) {
changeDict = [self changeDictForKVOChange:change];
}
}
if ( changeDict != nil ) {
((void(*)(id, SEL, NSDictionary *))objc_msgSend)(target, action, changeDict);
}
else {
((void(*)(id, SEL))objc_msgSend)(self.target, self.action);
((void(*)(id, SEL))objc_msgSend)(target, action);
}
}
}
@@ -387,35 +377,51 @@ void rz_swizzleDeallocIfNeeded(Class class);
- (void)invalidate
{
[[self.target rz_dependentObservers] removeObserver:self];
[[self.observedObject rz_registeredObservers] removeObject:self];
id observedObject = self.observedObject;
[rz_dependentObservers(self.target) removeObserver:self];
[rz_registeredObservers(observedObject) removeObserver:self];
// KVO throws an exception when removing an observer that was never added.
// This should never be a problem given how things are setup, but make sure to avoid a crash.
@try {
[self.observedObject removeObserver:self forKeyPath:self.keyPath context:kRZDBKVOContext];
[observedObject removeObserver:self forKeyPath:self.keyPath context:kRZDBKVOContext];
}
@catch (__unused NSException *exception) {
RZDBLog(@"RZDataBinding attempted to remove an observer from object:%@, but the observer was never added. This shouldn't have happened, but won't affect anything going forward.", self.observedObject);
RZDBLog(@"RZDataBinding attempted to remove an observer from object:%@, but the observer was never added. This shouldn't have happened, but won't affect anything going forward.", observedObject);
}
@synchronized (self) {
self.observedObject = nil;
self.target = nil;
self.action = NULL;
self.methodSignature = nil;
}
self.observedObject = nil;
self.target = nil;
self.action = NULL;
self.methodSignature = nil;
}
@end
#pragma mark - RZDBObserverContainer implementation
@implementation RZDBObserverContainer
@implementation RZDBObserverContainer {
NSHashTable *_observers;
}
- (instancetype)init
+ (instancetype)strongContainer
{
return [[self alloc] initWithBackingStore:[NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality]];
}
+ (instancetype)weakContainer
{
return [[self alloc] initWithBackingStore:[NSHashTable weakObjectsHashTable]];
}
- (instancetype)initWithBackingStore:(NSHashTable *)backingStore
{
self = [super init];
if ( self != nil ) {
_observers = [NSHashTable weakObjectsHashTable];
_observers = backingStore;
}
return self;
}
@@ -423,14 +429,36 @@ void rz_swizzleDeallocIfNeeded(Class class);
- (void)addObserver:(RZDBObserver *)observer
{
@synchronized (self) {
[self.observers addObject:observer];
[_observers addObject:observer];
}
}
- (void)removeObserver:(RZDBObserver *)observer
{
@synchronized (self) {
[self.observers removeObject:observer];
[_observers removeObject:observer];
}
}
- (void)enumerateObserversUsingBlock:(void (^)(RZDBObserver *, BOOL *))block
{
@synchronized (self) {
NSHashTable *observers = ^{
@synchronized (_observers) {
return [_observers copy];
}
}();
BOOL stop = NO;
for ( RZDBObserver *observer in observers ) {
if ( observer != nil ) {
block(observer, &stop);
}
if ( stop ) {
break;
}
}
}
}