Forked from vgrichina/NSObject+KVOWeakPropertyDebug.h
Last active
April 18, 2016 18:37
-
-
Save seanm/00938c5f6e456db8fcb1 to your computer and use it in GitHub Desktop.
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-2014 Vladimir Grichina. All rights reserved. | |
// | |
#import "NSObject+KVOWeakPropertyDebug.h" | |
#import <objc/runtime.h> | |
static 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); | |
} | |
} | |
static BOOL DoesPropertyTypeStringIncludeWeak(const char* string) | |
{ | |
// Assume the string is ASCII. | |
// Traverse the string char by char, ignore everything before the first comma, return YES if a 'W' is found after it, NO otherwise. | |
size_t strLen = string ? strlen(string) : 0; | |
BOOL foundFirstComma = NO; | |
for (size_t i = 0; i < strLen; i++) { | |
if (string[i] == ',') { | |
foundFirstComma = YES; | |
} | |
else if (foundFirstComma && (string[i] == 'W')) { | |
return YES; | |
} | |
} | |
return NO; | |
} | |
@implementation NSObject (KVOWeakPropertyDebug) | |
+ (void)load | |
{ | |
MethodSwizzle(self, @selector(addObserver:forKeyPath:options:context:), @selector(private_addObserver:forKeyPath:options:context:)); | |
MethodSwizzle(self, @selector(addObserver:toObjectsAtIndexes:forKeyPath:options:context:), @selector(private_addObserver:toObjectsAtIndexes:forKeyPath:options:context:)); | |
} | |
- (BOOL)private_isWeak:(NSString *)keyPath | |
{ | |
BOOL isWeak = NO; | |
// TODO: Support complex keyPath variants. Until then, keep just what's before the first '.' | |
char* copy = strdup(keyPath.UTF8String); | |
assert(copy); | |
copy = strsep(©, "."); | |
assert(copy); | |
objc_property_t property = class_getProperty(self.class, copy); | |
if (property) { | |
const char* tmp = property_getAttributes(property); | |
isWeak = DoesPropertyTypeStringIncludeWeak(tmp); | |
} | |
free(copy); | |
return isWeak; | |
} | |
- (void)private_addObserver:(NSObject *)observer | |
forKeyPath:(NSString *)keyPath | |
options:(NSKeyValueObservingOptions)options | |
context:(void *)context | |
{ | |
if ([self private_isWeak:keyPath]) { | |
NSLog(@"WARNING: object %p is observing '%@' property, which is weak and so isn't KVO-compliant", observer, keyPath); | |
} | |
[self private_addObserver:observer | |
forKeyPath:keyPath | |
options:options | |
context:context]; | |
} | |
- (void)private_addObserver:(NSObject *)observer | |
toObjectsAtIndexes:(NSIndexSet *)indexes | |
forKeyPath:(NSString *)keyPath | |
options:(NSKeyValueObservingOptions)options | |
context:(void *)context | |
{ | |
if ([self private_isWeak:keyPath]) { | |
NSLog(@"WARNING: object %p is observing '%@' property, which is weak and so isn't KVO-compliant", observer, keyPath); | |
} | |
[self private_addObserver:observer | |
toObjectsAtIndexes:indexes | |
forKeyPath:keyPath | |
options:options | |
context:context]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
On 10.11 we need something like
static BOOL DoesPropertyTypeStringIncludeWeak(const char* string)
{
return strstr(string, ",W,") != NULL ? YES : NO; // 10.11 variant
}