4

我有一个类,它基本上充当另一个类的轻量级包装类。它将其他类作为 iVar。我希望能够公开 iVar 的某些属性(实际上是很多),但要这样做,我必须像这样写出每个属性访问器:

- (void) setProperty:(Class *)value{
    _iVar.property = value;
}
- (Class *) property{
    return  _iVar.property;
}

当然,我必须对每一个属性都这样做,这很痛苦(大约有 30 个)。我希望能够合成它,但我无法弄清楚如何合成。

可以合成吗?

另外,我不能子类化....好吧,我也许可以,但真的不推荐。iVar 类真的很重(它实现了 CoreText)。我宁愿手工写出方法。

4

2 回答 2

4

好的,这就是我找到的解决方案……一旦你知道该怎么做,结果就很简单了。首先覆盖 '- (id) forwardingTargetForSelector:(SEL)aSelector' 并返回 iVar:

- (id) forwardingTargetForSelector:(SEL)aSelector{
    return iVar;
}

当运行时正在寻找一个方法而找不到一个方法时,它会调用这个方法来查看是否有另一个对象可以将消息转发到。请注意,此方法通常返回 nil,如果您在此处返回 nil,您的程序将崩溃(这是适当的行为)。

问题的第二部分是在您尝试发送未声明的消息时隐藏编译器错误/警告。这很容易通过声明一个您没有实现的类别来完成。

@interface Class (iVarClassMethods)
@propoperty (strong) Class *property1;
......more properties
@end

只要您不在任何地方(即 aka )放入实现,@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

现在,如果您需要更改任何要转发的属性/方法,您可以在协议中更改它们。然后,当您尝试将错误的方法发送到转发类时,编译器会警告您。

于 2012-02-23T19:10:53.410 回答
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,否则编译器会抱怨你的类没有实现这些方法。当然,如果你能想出一些没有这些技巧的更好的设计,那将是最好的。

于 2012-02-23T15:20:50.793 回答