我有一个类,它基本上作为另一个类的轻量级包装类。它认为其他类作为iVar。我希望能够暴露iVar的某些属性(实际上有很多),但为了这样做,我必须写出每个属性访问器,如下所示:
- (void) setProperty:(Class *)value{
_iVar.property = value;
}
- (Class *) property{
return _iVar.property;
}
当然,我必须为每一个属性做这个,这是一个痛苦(大约有30个)。我希望能够合成这个,但我无法弄清楚如何。
是否可以合成?
另外,我不能继承....好吧,我可能会,但它真的不推荐。 iVar类非常重(它实现了CoreText)。我宁愿手工写出这些方法。
答案 0 :(得分:4)
好的,所以这里是我找到的解决方案......一旦你知道该做什么,最终变得非常简单。首先覆盖' - (id)forwardingTargetForSelector:(SEL)aSelector'并返回iVar:
- (id) forwardingTargetForSelector:(SEL)aSelector{
return iVar;
}
当运行时查找方法但找不到方法时,它将调用此方法以查看是否有另一个对象将消息转发到。请注意,此方法通常返回nil,如果此处返回nil,则程序将崩溃(这是适当的行为)。
问题的第二部分是当您尝试发送未声明的消息时,会扼杀编译器错误/警告。通过声明未实现的类别可以轻松完成此操作。
@interface Class (iVarClassMethods)
@propoperty (strong) Class *property1;
......more properties
@end
只要您不在任何地方(即@implementation Class (category)
)放置实现,编译器就不会抱怨(它会假设实现某处...... )。
现在唯一的缺点是,如果你更改了iVar类接口中的任何属性,你需要确保更新所有其他使用上述方法的类,否则你会在另一个类时崩溃尝试发送现在错误的方法(编译器不会事先警告你)。但是,这个可以得到。您可以在类别中声明协议。因此,您可以为iVar类创建单独的协议,并将您希望的方法/属性从iVar类移动到协议中。
@protocol iVarClassProtocol
@propoperty (strong) Class *property1;
......more properties
@end
将该协议添加到iVar子类中,以便它现在具有通过协议声明的那些方法。
@interface iVarClass <iVarClassProtocol>
....other methods/properties you don't need forwarded
@end
最后,只需将协议添加到类别中即可。因此,您将拥有明确的声明,而不是前面提到的类别:
@interface Class (iVarClassMethods) <iVarClassProtocol>
@end
现在,如果您需要更改任何要转发的属性/方法,请在协议中更改它们。当您尝试将错误的方法发送到转发类时,编译器将发出警告。
答案 1 :(得分:2)
我认为您可以将消息转发给ivar:
- (void) forwardInvocation: (NSInvocation*) invocation
{
[invocation invokeWithTarget:ivar];
}
- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
NSMethodSignature *our = [super methodSignatureForSelector:selector];
NSMethodSignature *ivars = [ivar methodSignatureForSelector:selector];
return our ? our : ivars;
}
然后你必须隐藏或伪造你的对象的类型,例如通过强制转换为id
,否则编译器会抱怨你的类没有实现这些方法。
当然,如果你能想出一些没有这些技巧的更好的设计,那将是最好的。