Skip to content

Commit 6bbcc55

Browse files
committed
Improve safeObject:respondsToSelector:
The old code assumes the object at least responds to respondsToSelector: which may not always be true. I also I think the old code was not quite correct for all cases anyway. Using the runtime functions ensures no methods are ever called on the object, and properly handles metaclass objects, in theory.
1 parent e63ea4b commit 6bbcc55

File tree

1 file changed

+12
-15
lines changed

1 file changed

+12
-15
lines changed

Classes/Utility/Runtime/FLEXRuntimeUtility.m

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ + (NSUInteger)fieldNameOffsetForTypeEncoding:(const FLEXTypeEncoding *)typeEncod
9898

9999
/// Could be nil
100100
+ (NSString *)safeDescriptionForObject:(id)object {
101-
// Don't assume that we have an NSObject subclass.
102-
// Check to make sure the object responds to the description method
101+
// Don't assume that we have an NSObject subclass; not all objects respond to -description
103102
if ([self safeObject:object respondsToSelector:@selector(description)]) {
104103
return [object description];
105104
}
@@ -111,8 +110,6 @@ + (NSString *)safeDescriptionForObject:(id)object {
111110
+ (NSString *)safeDebugDescriptionForObject:(id)object {
112111
NSString *description = nil;
113112

114-
// Don't assume that we have an NSObject subclass.
115-
// Check to make sure the object responds to the description method
116113
if ([self safeObject:object respondsToSelector:@selector(debugDescription)]) {
117114
description = [object debugDescription];
118115
} else {
@@ -177,18 +174,18 @@ + (BOOL)safeObject:(id)object isKindOfClass:(Class)cls {
177174
}
178175

179176
+ (BOOL)safeObject:(id)object respondsToSelector:(SEL)sel {
180-
static BOOL (*respondsToSelector)(id, SEL, SEL) = nil;
181-
static BOOL (*respondsToSelector_meta)(id, SEL, SEL) = nil;
182-
static dispatch_once_t onceToken;
183-
dispatch_once(&onceToken, ^{
184-
respondsToSelector = (BOOL(*)(id, SEL, SEL))[NSObject instanceMethodForSelector:@selector(respondsToSelector:)];
185-
respondsToSelector_meta = (BOOL(*)(id, SEL, SEL))[NSObject methodForSelector:@selector(respondsToSelector:)];
186-
});
187-
177+
// If we're given a class, we want to know if classes respond to this selector.
178+
// Similarly, if we're given an instance, we want to know if instances respond.
188179
BOOL isClass = object_isClass(object);
189-
return (isClass ? respondsToSelector_meta : respondsToSelector)(
190-
object, @selector(respondsToSelector:), sel
191-
);
180+
Class cls = isClass ? object : object_getClass(object);
181+
// BOOL isMetaclass = class_isMetaClass(cls);
182+
183+
if (isClass) {
184+
// In theory, this should also work for metaclasses...
185+
return class_getClassMethod(cls, sel) != nil;
186+
} else {
187+
return class_getInstanceMethod(cls, sel) != nil;
188+
}
192189
}
193190

194191

0 commit comments

Comments
 (0)