Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
@vgrichina

This comment has been minimized.

Copy link
Owner Author

vgrichina commented Jan 12, 2013

@steipete

This comment has been minimized.

Copy link

steipete commented Jul 28, 2014

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

This comment has been minimized.

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
You can’t perform that action at this time.