Skip to content
Browse files

KVOHelp

  • Loading branch information...
1 parent 39f28cb commit b44366815313ceceae1cf2f7b77cdd7c47df5dfb @drewcrawford committed Feb 21, 2013
Showing with 86 additions and 0 deletions.
  1. +18 −0 DCAKit.xcodeproj/project.pbxproj
  2. +1 −0 DCAKit/DCAKit.h
  3. +24 −0 DCAKit/NSObject+KVOHelp.h
  4. +43 −0 DCAKit/NSObject+KVOHelp.m
View
18 DCAKit.xcodeproj/project.pbxproj
@@ -23,6 +23,9 @@
3A84838016D5EA4A00927A33 /* NSError+LessTerrible.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A84837E16D5EA4A00927A33 /* NSError+LessTerrible.h */; };
3A84838116D5EA4A00927A33 /* NSError+LessTerrible.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A84837F16D5EA4A00927A33 /* NSError+LessTerrible.m */; };
3A84838216D5EA4D00927A33 /* NSError+LessTerrible.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A84837E16D5EA4A00927A33 /* NSError+LessTerrible.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 3A84838816D6035900927A33 /* NSObject+KVOHelp.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A84838616D6035900927A33 /* NSObject+KVOHelp.h */; };
+ 3A84838916D6035900927A33 /* NSObject+KVOHelp.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A84838716D6035900927A33 /* NSObject+KVOHelp.m */; };
+ 3A84838A16D6035C00927A33 /* NSObject+KVOHelp.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A84838616D6035900927A33 /* NSObject+KVOHelp.h */; settings = {ATTRIBUTES = (Public, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -72,6 +75,8 @@
3A84836B16D5DFB100927A33 /* DCAKitHeaders.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DCAKitHeaders.m; sourceTree = "<group>"; };
3A84837E16D5EA4A00927A33 /* NSError+LessTerrible.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+LessTerrible.h"; sourceTree = "<group>"; };
3A84837F16D5EA4A00927A33 /* NSError+LessTerrible.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+LessTerrible.m"; sourceTree = "<group>"; };
+ 3A84838616D6035900927A33 /* NSObject+KVOHelp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+KVOHelp.h"; sourceTree = "<group>"; };
+ 3A84838716D6035900927A33 /* NSObject+KVOHelp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+KVOHelp.m"; sourceTree = "<group>"; };
BE4181CB14B38C93000251A7 /* DCAKit-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DCAKit-Info.plist"; sourceTree = "<group>"; };
BE4181CD14B38C93000251A7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
BE4181CF14B38C93000251A7 /* DCAKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DCAKit-Prefix.pch"; sourceTree = "<group>"; };
@@ -114,6 +119,7 @@
3A84833916D5DBB200927A33 /* DCAKit */ = {
isa = PBXGroup;
children = (
+ 3A84838516D6034C00927A33 /* KVOHelp */,
3A84837D16D5EA3A00927A33 /* NSError */,
3A84837C16D5EA0D00927A33 /* DCASimpleKeychain */,
3A84837B16D5E9FD00927A33 /* NSRegularExpression */,
@@ -198,6 +204,15 @@
name = NSError;
sourceTree = "<group>";
};
+ 3A84838516D6034C00927A33 /* KVOHelp */ = {
+ isa = PBXGroup;
+ children = (
+ 3A84838616D6035900927A33 /* NSObject+KVOHelp.h */,
+ 3A84838716D6035900927A33 /* NSObject+KVOHelp.m */,
+ );
+ name = KVOHelp;
+ sourceTree = "<group>";
+ };
BE4181B914B38C92000251A7 = {
isa = PBXGroup;
children = (
@@ -277,6 +292,7 @@
files = (
3A84835D16D5DBE200927A33 /* DCASimpleKeychain.h in Headers */,
3A84838016D5EA4A00927A33 /* NSError+LessTerrible.h in Headers */,
+ 3A84838816D6035900927A33 /* NSObject+KVOHelp.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -287,6 +303,7 @@
3A84837116D5DFCF00927A33 /* DCASimpleKeychain.h in Headers */,
3A84837216D5DFD600927A33 /* DCAKit.h in Headers */,
3A84838216D5EA4D00927A33 /* NSError+LessTerrible.h in Headers */,
+ 3A84838A16D6035C00927A33 /* NSObject+KVOHelp.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -411,6 +428,7 @@
3A84833F16D5DBB200927A33 /* DCAKit.m in Sources */,
3A84835B16D5DBC800927A33 /* DCASimpleKeychain.m in Sources */,
3A84838116D5EA4A00927A33 /* NSError+LessTerrible.m in Sources */,
+ 3A84838916D6035900927A33 /* NSObject+KVOHelp.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
1 DCAKit/DCAKit.h
@@ -9,6 +9,7 @@
#import <Foundation/Foundation.h>
#import <DCAKit/DCASimpleKeychain.h>
#import <DCAKit/NSError+LessTerrible.h>
+#import <DCAKit/NSObject+KVOHelp.h>
@interface DCAKit : NSObject
@end
View
24 DCAKit/NSObject+KVOHelp.h
@@ -0,0 +1,24 @@
+//
+// NSObject+KVOHelp.h
+// CoreDataHelp
+//
+// Created by Drew Crawford on 2/14/13.
+//
+//
+
+#import <Foundation/Foundation.h>
+
+@interface NSObject (KVOHelp)
+typedef void(^Observe)(id observer_ref, id object, NSString *keyPath, NSDictionary *change, void *context);
+
+/**
+ Blocks-based KVO.
+
+ 1) If you follow the warning, your observer stops when the observer_ref is cleaned up automatically. We also stop when the future is cleaned up.
+ 2) Currently there can only be one block-based observer on an object at a time... Calling this again replaces the existing observer. This is convenient e.g. for UICollectionViews and other flywheel-based views.
+
+ @param observer_ref Probably self. It's a bug to retain self in your block, so we pass you a special version you can use called observer_ref.
+
+ @warning Don't get capture a strong reference either to self or to the object in your block; this leads to weird memory issues. Instead, use the values that are helpfully passed in.*/
+-(void) addObserverWithRef:(id) observer_ref keypath:(NSString*) keypath options:(NSKeyValueObservingOptions) options context:(void*) context block:(Observe) block;
+@end
View
43 DCAKit/NSObject+KVOHelp.m
@@ -0,0 +1,43 @@
+//
+// NSObject+KVOHelp.m
+// CoreDataHelp
+//
+// Created by Drew Crawford on 2/14/13.
+//
+//
+
+#import "NSObject+KVOHelp.h"
+#import <objc/runtime.h>
+static const char *observerKey = "ObserverKey";
+@interface ObserverObj : NSObject {
+ @public
+ Observe block;
+ __weak id observer_ref;
+ NSString *_keyPath;
+}
+
+@end
+@implementation ObserverObj
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
+ if (!observer_ref) {
+ [object removeObserver:self forKeyPath:keyPath];
+ return;
+ }
+ block(observer_ref,object,keyPath,change,context);
+}
+
+@end
+@implementation NSObject (KVOHelp)
+-(void) addObserverWithRef:(id) observer_ref keypath:(NSString*) keypath options:(NSKeyValueObservingOptions) options context:(void*) context block:(Observe) block {
+ ObserverObj *oldObserver = (objc_getAssociatedObject(self, observerKey));
+ if (oldObserver) [self removeObserver:oldObserver forKeyPath:oldObserver->_keyPath];
+ ObserverObj *obj = [[ObserverObj alloc] init];
+ obj->observer_ref = observer_ref;
+ obj->block = block;
+ obj->_keyPath = keypath;
+ objc_setAssociatedObject(self, observerKey, obj, OBJC_ASSOCIATION_RETAIN);
+
+ [self addObserver:obj forKeyPath:keypath options:options context:context];
+}
+@end

0 comments on commit b443668

Please sign in to comment.
Something went wrong with that request. Please try again.