Skip to content

Commit bf5dfcb

Browse files
committed
Add Detailed Error Feedback for Unrecognized Selector
1 parent 384b916 commit bf5dfcb

File tree

1 file changed

+23
-43
lines changed

1 file changed

+23
-43
lines changed

OCRunner/RunnerClasses+Execute.m

Lines changed: 23 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ - (nullable MFValue *)execute:(MFScopeChain *)scope {
442442

443443
@implementation ORMethodCall(Execute)
444444
#if DEBUG
445-
// 尝试寻找被重写的 getter/setter 方法
445+
// 尝试寻找属性被重写的 getter/setter 方法或从 methodList 查找方法
446446
- (NSString *)unrecognizedSelectorTip:(id)instance
447447
{
448448
NSString *currentName = self.selectorName;
@@ -451,58 +451,36 @@ - (NSString *)unrecognizedSelectorTip:(id)instance
451451
currentName = [currentName substringWithRange:NSMakeRange(3, currentName.length - 4)];
452452
currentName = [[currentName substringToIndex:1].lowercaseString stringByAppendingString:[currentName substringFromIndex:1]];
453453
}
454-
NSMutableString *tip = [NSMutableString stringWithFormat:@"%@ Unrecognized selector '%@'", instance, currentName];
455-
Class class = object_isClass(instance) ? objc_getMetaClass(class_getName(instance)) : [instance class];
454+
NSMutableString *tip = [NSMutableString stringWithFormat:@"OCRunner Error: %@ Unrecognized selector '%@'", instance, currentName];
455+
if (object_isClass(instance)) {
456+
return tip;
457+
}
458+
Class class = [instance class];
456459

457-
// 1、先尝试通过 class_copyPropertyList 查找属性的 getter/setter 方法,如
460+
// 1、先尝试通过 propertyList 查找属性的 getter/setter 方法,如
458461
// @property(nonatomic, assign, getter=customGetterTest, setter=customSetterTest:) BOOL test;
459-
Class propertyClass = class.mutableCopy;
460-
while (propertyClass && propertyClass != NSObject.class) {
461-
unsigned int propertyCount;
462-
objc_property_t *properties = class_copyPropertyList(propertyClass, &propertyCount);
463-
for (int i = 0; i < propertyCount; i++) {
464-
objc_property_t property = properties[i];
465-
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
466-
if ([propertyName isEqualToString:currentName]) {
467-
NSString *foundName = [NSString stringWithUTF8String:property_copyAttributeValue(property, self.isAssignedValue ? "S" : "G")];
468-
if (foundName.length && [instance respondsToSelector:NSSelectorFromString(foundName)]) {
469-
if (propertyClass == class) {
470-
[tip appendFormat:@",but found %@ method '%@', please check if you need to call this method", self.isAssignedValue ? @"setter" : @"getter", foundName];
471-
} else {
472-
[tip appendFormat:@",but found %@ method '%@' in parent class %@, please check if you need to call this method", self.isAssignedValue ? @"setter" : @"getter", foundName, NSStringFromClass(propertyClass)];
473-
}
474-
free(properties);
475-
return tip;
476-
}
462+
objc_property_t property = class_getProperty(class, currentName.UTF8String);
463+
if (property) {
464+
char *attributeValue = property_copyAttributeValue(property, self.isAssignedValue ? "S" : "G");
465+
if (attributeValue) {
466+
NSString *foundName = [NSString stringWithUTF8String:attributeValue];
467+
free(attributeValue);
468+
if (foundName.length && [instance respondsToSelector:NSSelectorFromString(foundName)]) {
469+
[tip appendFormat:@",but found %@ method '%@', please check if you need to call this method", self.isAssignedValue ? @"setter" : @"getter", foundName];
470+
return tip;
477471
}
478472
}
479-
free(properties);
480-
propertyClass = class_getSuperclass(propertyClass);
481473
}
482474

483-
// 2、未找到则尝试手动拼接 getter/setter 方法名并从 class_copyMethodList 查找,如
475+
// 2、未找到则尝试手动拼接 getter/setter 方法名并从 methodList 查找,如
484476
// @interface UIView(UIViewRendering)
485477
// @property(nonatomic,getter=isHidden) BOOL hidden;
486478
// @end
487479
currentName = [NSString stringWithFormat:@"%@%@%@", self.isAssignedValue ? @"set" : @"is", [[currentName substringToIndex:1] uppercaseString], [currentName substringFromIndex:1]];
488-
Class methodClass = class.mutableCopy;
489-
while (methodClass && methodClass != NSObject.class) {
490-
unsigned int methodCount;
491-
Method *methods = class_copyMethodList(methodClass, &methodCount);
492-
for (int i = 0; i < methodCount; i++) {
493-
Method method = methods[i];
494-
SEL sel = method_getName(method);
495-
NSString *methodName = NSStringFromSelector(sel);
496-
if ([methodName isEqualToString:currentName]) {
497-
if ([instance respondsToSelector:sel]) {
498-
[tip appendFormat:@",but found %@ method '%@', please check if you need to call this method", self.isAssignedValue ? @"setter" : @"getter", currentName];
499-
free(methods);
500-
return tip;
501-
}
502-
}
503-
}
504-
free(methods);
505-
methodClass = class_getSuperclass(methodClass);
480+
Method method = class_getInstanceMethod(class, NSSelectorFromString(currentName));
481+
if (method && [instance respondsToSelector:NSSelectorFromString(currentName)]) {
482+
[tip appendFormat:@",but found %@ method '%@', please check if you need to call this method", self.isAssignedValue ? @"setter" : @"getter", currentName];
483+
return tip;
506484
}
507485

508486
return tip;
@@ -591,6 +569,8 @@ - (nullable MFValue *)execute:(MFScopeChain *)scope {
591569
#if DEBUG
592570
NSLog(@"%@", [self unrecognizedSelectorTip:instance]);
593571
NSAssert(false, @"As mentioned above");
572+
#else
573+
NSLog(@"OCRunner Error: %@ Unrecognized selector '%@'", instance, self.selectorName);
594574
#endif
595575
return [MFValue nullValue];
596576
}

0 commit comments

Comments
 (0)