我正在构建一个表单库,用户可以在其中继承我的基本表单元素并提供自己的表单元素,同时还可以选择性地提供我的FormTheme
类的子类,以便为这些元素提供额外的样式。
我在themeClass
基类上有一个属性FormElement
,用户可以将其设置为他们创建的自定义主题类。如果他们没有手动设置,我有这个方法:
- (Class)defaultThemeClass {
NSString *className = NSStringFromClass([self class]);
NSString *themeClassName = [className stringByAppendingString:@"Theme"];
return NSClassFromString(themeClassName);
}
只接受元素类名称并将Theme
附加到其中。 (我的库使用命名约定,其中元素类可能被称为FormTableElement
,相应的单元格和主题类将是FormTableCell
和FormTableElementTheme
)
在我的基本表单元素类中,我覆盖了themeClass
- (Class)themeClass {
if(_themeClass) return _themeClass;
Class defaultClass = [self defaultThemeClass];
if(defaultClass) return defaultClass;
else return NSClassFromString(@"FormElementTheme");
}
这很简单,如果用户设置了它使用的自定义主题类,如果没有,它将尝试根据defaultThemeClass
的命名约定获取主题类。如果这两个失败了,那么随库提供的默认主题类被选中并且一切都很好。
但是,我遇到了一种情况,我没想到基本表单元素上有多个子类级别,如下所示:
FormElement
- FormTableRowElement
- FormTableRowDetailElement
然而,这里只有两个具体的主题类,FormElementTheme
和FormTableRowElementTheme
。此外,FormTableRowDetailElement
使用其超类的主题元素(FormTableRowElementTheme
)的属性,但`themeClass只返回自定义类,该元素的默认类或所有元素的超类的主题类
我真正需要的是这样的事情:
- (Class)themeClass {
if(_themeClass) return _themeClass;
Class defaultClass = [self defaultThemeClass];
if(defaultClass) return defaultClass;
else if([super respondsToSelector:@selector(themeClass)]) {
SEL themeSelector = @selector(themeClass);
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[super class] instanceMethodSignatureForSelector:themeSelector]];
[invocation setSelector:themeSelector];
invocation.target = super;
[invocation invoke];
Class returnValue;
[invocation getReturnValue:&returnValue];
return returnValue;
}
else return NSClassFromString(@"FormElementTheme");
}
如果该元素不存在主题元素类,它将继续查找超类链,直到超类不响应该方法,在这种情况下它将默认为基类主题或它确实找到中间主题类并返回。
问题当然是super
不是对象,而是编译器使用的关键字,因此您无法将NSInvocation
的目标设置为super
。< / p>
我需要一种方法来实现相同的效果,在继承链上传播方法,并且必须在基类中定义,因为每个子类都不能负责实现此方法或提供自己的主题类(对最终用户造成太大负担。)
编辑:
另一个问题是,FormElement
是NSObject
的子类,因此任何尝试调出[super themeClass]
错误的行为都会出现。
答案 0 :(得分:0)
我打赌你可以做这样的工作:
class_respondsToSelector([self superclass], @selector(themeClass))
请注意class_respondsToSelector
是指响应选择器的类的实例。
修改强>
要调用超级方法,您可以:
static Class (*_method_invoke_class)(id, Method, ...) = (Class (*)(id, Method, ...)) method_invoke;
Method m = class_getInstanceMethod( [self superclass], @selector(themeClass) );
Class c = _method_invoke_class( self, m );