Created
January 12, 2013 01:09
-
-
Save vgrichina/4515445 to your computer and use it in GitHub Desktop.
NSObject category that logs calls to addObserver for weak properties (as they aren't fully KVO-compliant)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSObject+KVOWeakPropertyDebug.h | |
// KVOWeakPropertyDebug | |
// | |
// Created by Vladimir Grichina on 12.01.13. | |
// Copyright (c) 2013 Vladimir Grichina. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
@interface NSObject (KVOWeakPropertyDebug) | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSObject+KVOWeakPropertyDebug.m | |
// KVOWeakPropertyDebug | |
// | |
// Created by Vladimir Grichina on 12.01.13. | |
// Copyright (c) 2013 Vladimir Grichina. All rights reserved. | |
// | |
#import "NSObject+KVOWeakPropertyDebug.h" | |
#import <objc/runtime.h> | |
void MethodSwizzle(Class c, SEL origSEL, SEL overrideSEL) | |
{ | |
Method origMethod = class_getInstanceMethod(c, origSEL); | |
Method overrideMethod = class_getInstanceMethod(c, overrideSEL); | |
if (class_addMethod(c, origSEL, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) { | |
class_replaceMethod(c, overrideSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); | |
} else { | |
method_exchangeImplementations(origMethod, overrideMethod); | |
} | |
} | |
@implementation NSObject (KVOWeakPropertyDebug) | |
+ (void)load | |
{ | |
MethodSwizzle(self, @selector(addObserver:forKeyPath:options:context:), @selector(_addObserver:forKeyPath:options:context:)); | |
} | |
- (BOOL)_isWeak:(NSString *)keyPath | |
{ | |
// TODO: Support complex keyPath variants | |
objc_property_t property = class_getProperty(self.class, keyPath.UTF8String); | |
if (property) { | |
return property_getAttributes(property)[3] == 'W'; | |
} | |
return NO; | |
} | |
- (void)_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context | |
{ | |
if ([self _isWeak:keyPath]) { | |
NSLog(@"WARNING: observing '%@' property, which is weak and so isn't fully KVO-compliant", keyPath); | |
} | |
[self _addObserver:observer forKeyPath:keyPath options:options context:context]; | |
} | |
@end |
property_getAttributes(property)[3] == 'W' is no longer safe. Modern compilers add more type data:
Printing description of attributes:
(const char *) attributes = 0x000000010fe8c3df "T@\"NSArray\",R,N"
So you need a more sophisticated string check to find the W property.
Thanks for creating this!
I've made a few improvements: 1) fixed what steipete pointed out (better check for 'W') 2) also swizzle and check addObserver:toObjectsAtIndexes:forKeyPath:options:context: 3) for keypaths, strip everything after the first dot. 4) renamed methods that start with underscore, which is reserved by Apple.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See here for more info http://www.componentix.com/blog/28/debug-usage-of-objectivec-weak-properties-with-kvo