在超类

时间:2015-08-24 17:54:25

标签: ios objective-c

我正在构建一个表单库,用户可以在其中继承我的基本表单元素并提供自己的表单元素,同时还可以选择性地提供我的FormTheme类的子类,以便为这些元素提供额外的样式。

我在themeClass基类上有一个属性FormElement,用户可以将其设置为他们创建的自定义主题类。如果他们没有手动设置,我有这个方法:

- (Class)defaultThemeClass {
    NSString *className = NSStringFromClass([self class]);
    NSString *themeClassName = [className stringByAppendingString:@"Theme"];
    return NSClassFromString(themeClassName);
}

只接受元素类名称并将Theme附加到其中。 (我的库使用命名约定,其中元素类可能被称为FormTableElement,相应的单元格和主题类将是FormTableCellFormTableElementTheme

在我的基本表单元素类中,我覆盖了themeClass

的getter
- (Class)themeClass {
    if(_themeClass) return _themeClass;
    Class defaultClass = [self defaultThemeClass];
    if(defaultClass) return defaultClass;
    else return NSClassFromString(@"FormElementTheme");
}

这很简单,如果用户设置了它使用的自定义主题类,如果没有,它将尝试根据defaultThemeClass的命名约定获取主题类。如果这两个失败了,那么随库提供的默认主题类被选中并且一切都很好。

但是,我遇到了一种情况,我没想到基本表单元素上有多个子类级别,如下所示:

FormElement
- FormTableRowElement
    - FormTableRowDetailElement

然而,这里只有两个具体的主题类,FormElementThemeFormTableRowElementTheme。此外,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>

我需要一种方法来实现相同的效果,在继承链上传播方法,并且必须在基类中定义,因为每个子类都不能负责实现此方法或提供自己的主题类(对最终用户造成太大负担。)

编辑:

另一个问题是,FormElementNSObject的子类,因此任何尝试调出[super themeClass]错误的行为都会出现。

1 个答案:

答案 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 );