- update
This commit is contained in:
1 parent
1bf4b9ef1d
commit
4e66c377fd
664 files changed
+14818
-10172
No files matched your search
+103
-75
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user