Permalink
Browse files

Added KVO Notification Center

  • Loading branch information...
1 parent a8a1e20 commit f2b2bec1f466fae0ed5d5a0c04c0f99d237b7b98 @logancollins committed Apr 3, 2012
@@ -7,6 +7,26 @@
objects = {
/* Begin PBXBuildFile section */
+ 02F2A6B6152B99B700414EE4 /* GXKVONotificationCenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6B4152B99B700414EE4 /* GXKVONotificationCenter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 02F2A6B7152B99B700414EE4 /* GXKVONotificationCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 02F2A6B5152B99B700414EE4 /* GXKVONotificationCenter.m */; };
+ 02F2A6BA152B9E6000414EE4 /* GXKVOObservation.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6B8152B9E5F00414EE4 /* GXKVOObservation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 02F2A6BB152B9E6000414EE4 /* GXKVOObservation.m in Sources */ = {isa = PBXBuildFile; fileRef = 02F2A6B9152B9E5F00414EE4 /* GXKVOObservation.m */; };
+ 02F2A6BE152B9F2B00414EE4 /* GXObjectKVOObservation.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6BC152B9F2A00414EE4 /* GXObjectKVOObservation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 02F2A6BF152B9F2B00414EE4 /* GXObjectKVOObservation.m in Sources */ = {isa = PBXBuildFile; fileRef = 02F2A6BD152B9F2B00414EE4 /* GXObjectKVOObservation.m */; };
+ 02F2A6C1152B9F5400414EE4 /* GXObjectKVOObservation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6C0152B9F5400414EE4 /* GXObjectKVOObservation_Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 02F2A6C2152B9F5E00414EE4 /* GXKVONotificationCenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6B4152B99B700414EE4 /* GXKVONotificationCenter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 02F2A6C3152B9F5E00414EE4 /* GXKVONotificationCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 02F2A6B5152B99B700414EE4 /* GXKVONotificationCenter.m */; };
+ 02F2A6C4152B9F5E00414EE4 /* GXKVOObservation.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6B8152B9E5F00414EE4 /* GXKVOObservation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 02F2A6C5152B9F5E00414EE4 /* GXKVOObservation.m in Sources */ = {isa = PBXBuildFile; fileRef = 02F2A6B9152B9E5F00414EE4 /* GXKVOObservation.m */; };
+ 02F2A6C6152B9F5E00414EE4 /* GXObjectKVOObservation.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6BC152B9F2A00414EE4 /* GXObjectKVOObservation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 02F2A6C7152B9F5E00414EE4 /* GXObjectKVOObservation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6C0152B9F5400414EE4 /* GXObjectKVOObservation_Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 02F2A6C8152B9F5E00414EE4 /* GXObjectKVOObservation.m in Sources */ = {isa = PBXBuildFile; fileRef = 02F2A6BD152B9F2B00414EE4 /* GXObjectKVOObservation.m */; };
+ 02F2A6CB152B9F8000414EE4 /* GXBlockKVOObservation.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6C9152B9F8000414EE4 /* GXBlockKVOObservation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 02F2A6CC152B9F8000414EE4 /* GXBlockKVOObservation.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6C9152B9F8000414EE4 /* GXBlockKVOObservation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 02F2A6CD152B9F8000414EE4 /* GXBlockKVOObservation.m in Sources */ = {isa = PBXBuildFile; fileRef = 02F2A6CA152B9F8000414EE4 /* GXBlockKVOObservation.m */; };
+ 02F2A6CE152B9F8000414EE4 /* GXBlockKVOObservation.m in Sources */ = {isa = PBXBuildFile; fileRef = 02F2A6CA152B9F8000414EE4 /* GXBlockKVOObservation.m */; };
+ 02F2A6D0152B9FAB00414EE4 /* GXBlockKVOObservation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6CF152B9FAB00414EE4 /* GXBlockKVOObservation_Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 02F2A6D1152B9FAB00414EE4 /* GXBlockKVOObservation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 02F2A6CF152B9FAB00414EE4 /* GXBlockKVOObservation_Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
EA091A1A150A92870033C7DF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = EA091A18150A92870033C7DF /* InfoPlist.strings */; };
EA091A1E150A92870033C7DF /* Graviton.m in Sources */ = {isa = PBXBuildFile; fileRef = EA091A1D150A92870033C7DF /* Graviton.m */; };
EA091A25150A92CA0033C7DF /* GravitonDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = EA091A24150A92CA0033C7DF /* GravitonDefines.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -27,6 +47,16 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
+ 02F2A6B4152B99B700414EE4 /* GXKVONotificationCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GXKVONotificationCenter.h; sourceTree = "<group>"; };
+ 02F2A6B5152B99B700414EE4 /* GXKVONotificationCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GXKVONotificationCenter.m; sourceTree = "<group>"; };
+ 02F2A6B8152B9E5F00414EE4 /* GXKVOObservation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GXKVOObservation.h; sourceTree = "<group>"; };
+ 02F2A6B9152B9E5F00414EE4 /* GXKVOObservation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GXKVOObservation.m; sourceTree = "<group>"; };
+ 02F2A6BC152B9F2A00414EE4 /* GXObjectKVOObservation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GXObjectKVOObservation.h; sourceTree = "<group>"; };
+ 02F2A6BD152B9F2B00414EE4 /* GXObjectKVOObservation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GXObjectKVOObservation.m; sourceTree = "<group>"; };
+ 02F2A6C0152B9F5400414EE4 /* GXObjectKVOObservation_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GXObjectKVOObservation_Private.h; sourceTree = "<group>"; };
+ 02F2A6C9152B9F8000414EE4 /* GXBlockKVOObservation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GXBlockKVOObservation.h; sourceTree = "<group>"; };
+ 02F2A6CA152B9F8000414EE4 /* GXBlockKVOObservation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GXBlockKVOObservation.m; sourceTree = "<group>"; };
+ 02F2A6CF152B9FAB00414EE4 /* GXBlockKVOObservation_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GXBlockKVOObservation_Private.h; sourceTree = "<group>"; };
EA091A0C150A92870033C7DF /* Graviton.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Graviton.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EA091A14150A92870033C7DF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
EA091A17150A92870033C7DF /* Graviton-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Graviton-Info.plist"; sourceTree = "<group>"; };
@@ -66,6 +96,23 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 02F2A6B2152B99A000414EE4 /* Notifications */ = {
+ isa = PBXGroup;
+ children = (
+ 02F2A6B4152B99B700414EE4 /* GXKVONotificationCenter.h */,
+ 02F2A6B5152B99B700414EE4 /* GXKVONotificationCenter.m */,
+ 02F2A6B8152B9E5F00414EE4 /* GXKVOObservation.h */,
+ 02F2A6B9152B9E5F00414EE4 /* GXKVOObservation.m */,
+ 02F2A6BC152B9F2A00414EE4 /* GXObjectKVOObservation.h */,
+ 02F2A6C0152B9F5400414EE4 /* GXObjectKVOObservation_Private.h */,
+ 02F2A6BD152B9F2B00414EE4 /* GXObjectKVOObservation.m */,
+ 02F2A6C9152B9F8000414EE4 /* GXBlockKVOObservation.h */,
+ 02F2A6CF152B9FAB00414EE4 /* GXBlockKVOObservation_Private.h */,
+ 02F2A6CA152B9F8000414EE4 /* GXBlockKVOObservation.m */,
+ );
+ path = Notifications;
+ sourceTree = "<group>";
+ };
EA091A00150A92860033C7DF = {
isa = PBXGroup;
children = (
@@ -101,6 +148,7 @@
EA091A1D150A92870033C7DF /* Graviton.m */,
EA091A24150A92CA0033C7DF /* GravitonDefines.h */,
EA091A28150A933A0033C7DF /* Files */,
+ 02F2A6B2152B99A000414EE4 /* Notifications */,
EA4424DC15193D6D00EA1C1B /* Categories */,
EA091A16150A92870033C7DF /* Supporting Files */,
);
@@ -164,6 +212,12 @@
EA091A2B150A93530033C7DF /* GXFileOperationQueue.h in Headers */,
EA091A2E150A935E0033C7DF /* GXFileOperationQueue_Private.h in Headers */,
EA4424E015193D7F00EA1C1B /* NSObject+GravitonAdditions.h in Headers */,
+ 02F2A6B6152B99B700414EE4 /* GXKVONotificationCenter.h in Headers */,
+ 02F2A6BA152B9E6000414EE4 /* GXKVOObservation.h in Headers */,
+ 02F2A6BE152B9F2B00414EE4 /* GXObjectKVOObservation.h in Headers */,
+ 02F2A6C1152B9F5400414EE4 /* GXObjectKVOObservation_Private.h in Headers */,
+ 02F2A6CB152B9F8000414EE4 /* GXBlockKVOObservation.h in Headers */,
+ 02F2A6D0152B9FAB00414EE4 /* GXBlockKVOObservation_Private.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -176,6 +230,12 @@
EA55FA4D151D35C80088F053 /* GXFileOperationQueue.h in Headers */,
EA55FA4E151D35C80088F053 /* NSObject+GravitonAdditions.h in Headers */,
EA55FA4F151D35CE0088F053 /* GXFileOperationQueue_Private.h in Headers */,
+ 02F2A6C2152B9F5E00414EE4 /* GXKVONotificationCenter.h in Headers */,
+ 02F2A6C4152B9F5E00414EE4 /* GXKVOObservation.h in Headers */,
+ 02F2A6C6152B9F5E00414EE4 /* GXObjectKVOObservation.h in Headers */,
+ 02F2A6C7152B9F5E00414EE4 /* GXObjectKVOObservation_Private.h in Headers */,
+ 02F2A6CC152B9F8000414EE4 /* GXBlockKVOObservation.h in Headers */,
+ 02F2A6D1152B9FAB00414EE4 /* GXBlockKVOObservation_Private.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -264,13 +324,21 @@
EA091A1E150A92870033C7DF /* Graviton.m in Sources */,
EA091A2C150A93530033C7DF /* GXFileOperationQueue.m in Sources */,
EA4424E115193D7F00EA1C1B /* NSObject+GravitonAdditions.m in Sources */,
+ 02F2A6B7152B99B700414EE4 /* GXKVONotificationCenter.m in Sources */,
+ 02F2A6BB152B9E6000414EE4 /* GXKVOObservation.m in Sources */,
+ 02F2A6BF152B9F2B00414EE4 /* GXObjectKVOObservation.m in Sources */,
+ 02F2A6CD152B9F8000414EE4 /* GXBlockKVOObservation.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EA55FA3B151D35A70088F053 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 02F2A6C3152B9F5E00414EE4 /* GXKVONotificationCenter.m in Sources */,
+ 02F2A6C5152B9F5E00414EE4 /* GXKVOObservation.m in Sources */,
+ 02F2A6C8152B9F5E00414EE4 /* GXObjectKVOObservation.m in Sources */,
+ 02F2A6CE152B9F8000414EE4 /* GXBlockKVOObservation.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -422,6 +490,7 @@
EA55FA48151D35A80088F053 /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
View
@@ -9,6 +9,7 @@
#import <Graviton/GravitonDefines.h>
#import <Graviton/GXFileOperationQueue.h>
+#import <Graviton/GXKVONotificationCenter.h>
#import <Graviton/NSObject+GravitonAdditions.h>
@@ -0,0 +1,24 @@
+//
+// GXBlockKVOObservation.h
+// Graviton
+//
+// Created by Logan Collins on 4/3/12.
+// Copyright (c) 2012 Sunflower Softworks. All rights reserved.
+//
+
+#import <Graviton/GXKVOObservation.h>
+
+
+@interface GXBlockKVOObservation : GXKVOObservation
+
++ (GXBlockKVOObservation *)observationWithObject:(id)object
+ keyPath:(NSString *)keyPath
+ options:(NSKeyValueObservingOptions)options
+ block:(void (^)(NSDictionary *change))block;
+
+@property (weak, readonly) id object;
+@property (copy, readonly) NSString *keyPath;
+@property (assign, readonly) NSKeyValueObservingOptions options;
+@property (copy, readonly) void (^block)(NSDictionary *change);
+
+@end
@@ -0,0 +1,56 @@
+//
+// GXBlockKVOObservation.m
+// Graviton
+//
+// Created by Logan Collins on 4/3/12.
+// Copyright (c) 2012 Sunflower Softworks. All rights reserved.
+//
+
+#import "GXBlockKVOObservation.h"
+#import "GXBlockKVOObservation_Private.h"
+
+
+static NSString * const GXBlockKVOObservationContext = @"GXBlockKVOObservationContext";
+
+
+@implementation GXBlockKVOObservation
+
+@synthesize object=_object;
+@synthesize keyPath=_keyPath;
+@synthesize options=_options;
+@synthesize block=_block;
+
++ (GXBlockKVOObservation *)observationWithObject:(id)object keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(void (^)(NSDictionary *))block {
+ return [[self alloc] initWithObject:object keyPath:keyPath options:options block:block];
+}
+
+- (id)initWithObject:(id)object
+ keyPath:(NSString *)keyPath
+ options:(NSKeyValueObservingOptions)options
+ block:(void (^)(NSDictionary *change))block {
+ self = [super init];
+ if (self) {
+ self.object = object;
+ self.keyPath = keyPath;
+ self.options = options;
+ self.block = block;
+
+ [self.object addObserver:self forKeyPath:self.keyPath options:self.options context:(__bridge void *)GXBlockKVOObservationContext];
+ }
+ return self;
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
+ if (context == (__bridge void *)GXBlockKVOObservationContext) {
+ if (self.block != nil) {
+ self.block(change);
+ }
+ }
+ else [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+}
+
+- (void)unregister {
+ [self.object removeObserver:self forKeyPath:self.keyPath];
+}
+
+@end
@@ -0,0 +1,24 @@
+//
+// GXBlockKVOObservation_Private.h
+// Graviton
+//
+// Created by Logan Collins on 4/3/12.
+// Copyright (c) 2012 Sunflower Softworks. All rights reserved.
+//
+
+#import <Graviton/GXBlockKVOObservation.h>
+
+
+@interface GXBlockKVOObservation ()
+
+- (id)initWithObject:(id)object
+ keyPath:(NSString *)keyPath
+ options:(NSKeyValueObservingOptions)options
+ block:(void (^)(NSDictionary *change))block;
+
+@property (weak, readwrite) id object;
+@property (copy, readwrite) NSString *keyPath;
+@property (assign, readwrite) NSKeyValueObservingOptions options;
+@property (copy, readwrite) void (^block)(NSDictionary *change);
+
+@end
@@ -0,0 +1,22 @@
+//
+// GXKVONotificationCenter.h
+// Graviton
+//
+// Created by Logan Collins on 4/3/12.
+// Copyright (c) 2012 Sunflower Softworks. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface GXKVONotificationCenter : NSObject
+
++ (GXKVONotificationCenter *)defaultCenter;
+
+- (void)addObserver:(id)observer object:(id)object keyPath:(NSString *)keyPath selector:(SEL)selector options:(NSKeyValueObservingOptions)options userInfo:(NSDictionary *)userInfo;
+- (id)addObserverForObject:(id)object keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(void (^)(NSDictionary *change))block;
+
+- (void)removeObserver:(id)observer;
+- (void)removeObserver:(id)observer object:(id)object keyPath:(NSString *)keyPath;
+
+@end
@@ -0,0 +1,91 @@
+//
+// GXKVONotificationCenter.m
+// Graviton
+//
+// Created by Logan Collins on 4/3/12.
+// Copyright (c) 2012 Sunflower Softworks. All rights reserved.
+//
+
+#import "GXKVONotificationCenter.h"
+
+#import "GXKVOObservation.h"
+#import "GXObjectKVOObservation.h"
+#import "GXBlockKVOObservation.h"
+
+
+@implementation GXKVONotificationCenter {
+ NSMutableDictionary *_observations;
+}
+
++ (GXKVONotificationCenter *)defaultCenter {
+ static GXKVONotificationCenter *defaultCenter = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ defaultCenter = [self new];
+ });
+ return defaultCenter;
+}
+
+- (id)init {
+ self = [super init];
+ if (self) {
+ _observations = [NSMutableDictionary dictionary];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ for (NSString *key in [_observations keyEnumerator]) {
+ GXKVOObservation *observation = [_observations objectForKey:key];
+ [observation unregister];
+ }
+}
+
+
+#pragma mark -
+#pragma mark Observers
+
+- (NSString *)keyForObserver:(id)observer object:(id)object keyPath:(NSString *)keyPath {
+ return [NSString stringWithFormat:@"%p:%p:%@", observer, object, keyPath];
+}
+
+- (void)addObserver:(id)observer object:(id)object keyPath:(NSString *)keyPath selector:(SEL)selector options:(NSKeyValueObservingOptions)options userInfo:(NSDictionary *)userInfo {
+ NSString *key = [self keyForObserver:observer object:object keyPath:keyPath];
+ GXObjectKVOObservation *observation = [_observations objectForKey:key];
+ if (observation == nil) {
+ observation = [GXObjectKVOObservation observationWithObserver:observer object:object keyPath:keyPath selector:selector options:options userInfo:userInfo];
+ [_observations setObject:observation forKey:key];
+ }
+}
+
+- (id)addObserverForObject:(id)object keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(void (^)(NSDictionary *change))block {
+ if (block == nil) {
+ return nil;
+ }
+
+ NSString *key = [self keyForObserver:block object:object keyPath:keyPath];
+ GXBlockKVOObservation *observation = [_observations objectForKey:key];
+ if (observation == nil) {
+ observation = [GXBlockKVOObservation observationWithObject:object keyPath:keyPath options:options block:block];
+ [_observations setObject:observation forKey:key];
+ }
+ return observation;
+}
+
+- (void)removeObserver:(id)observer {
+ [self removeObserver:observer object:nil keyPath:nil];
+}
+
+- (void)removeObserver:(id)observer object:(id)object keyPath:(NSString *)keyPath {
+ id observerObject = observer;
+ if ([observer isKindOfClass:[GXBlockKVOObservation class]]) {
+ observerObject = [observer block];
+ }
+
+ NSString *key = [self keyForObserver:observerObject object:object keyPath:keyPath];
+ GXKVOObservation *observation = [_observations objectForKey:key];
+ [observation unregister];
+ [_observations removeObjectForKey:key];
+}
+
+@end
@@ -0,0 +1,16 @@
+//
+// GXKVOObservation.h
+// Graviton
+//
+// Created by Logan Collins on 4/3/12.
+// Copyright (c) 2012 Sunflower Softworks. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface GXKVOObservation : NSObject
+
+- (void)unregister;
+
+@end
@@ -0,0 +1,18 @@
+//
+// GXKVOObservation.m
+// Graviton
+//
+// Created by Logan Collins on 4/3/12.
+// Copyright (c) 2012 Sunflower Softworks. All rights reserved.
+//
+
+#import "GXKVOObservation.h"
+
+
+@implementation GXKVOObservation
+
+- (void)unregister {
+ // no-op
+}
+
+@end
Oops, something went wrong.

0 comments on commit f2b2bec

Please sign in to comment.