Skip to content

Instantly share code, notes, and snippets.

@vgrichina
Created January 12, 2013 01:09
Show Gist options
  • Save vgrichina/4515445 to your computer and use it in GitHub Desktop.
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)
//
// 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
//
// 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
@steipete
Copy link

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.

@seanm
Copy link

seanm commented Jul 31, 2014

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.

https://gist.github.com/seanm/00938c5f6e456db8fcb1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment