【问题标题】:Does Objective-C feature runtime methods for Protocol message forwarding?Objective-C 是否为协议消息转发提供运行时方法?
【发布时间】:2015-11-13 11:34:35
【问题描述】:

我经常这样使用协议:

@protocol AnotherObjectDelegate <NSObject>
-(void)someMethodWithObject:(id)object;
@end
@interface AnotherObject : NSObject
@property (assign) id<AnotherObjectDelegate> delegate;
@end

我的 BaseObject 确实符合该协议,并且也是接收来自 AnotherObject 的消息的委托。

@interface BaseObject : NSObject <AnotherObjectDelegate>
@property AnotherObject* anotherObject;
@property SecondLevelObject* secondLevelObject;
@end

@implementation BaseObject
-(instancetype)init {
    if (self = [super init]) {
        self.anotherObject = [AnotherObject new];
        self.anotherObject.delegate = self;
    }
}
-(void)someMethodWithObject:(id)object {
    // Forwarding Message from Delegate to other Object conforming to protocol:
    [self.secondLevelObject someMethodWithObject:object];
}
@end

然而,BaseObject-Instance 充当某种代理,让其他实例将协议消息转发到 BaseObject 之后的对象所拥有的其他对象:

@interface SecondLevelObject : NSObject <AnotherObjectDelegate>
@property ThirdLevelObject* thirdLevelObject;
@end

@implementation SecondLevelObject
-(void)someMethodWithObject:(id)object {
    [self.thirdLevelObject someMethodWithObject:object];
}
@end

在 SecondLevelObject 中有一个 ThirdLevelObject 也符合相同的协议。在这里,我还转发了消息 - 因此 SecondLevelObjects 也充当某种代理。

@interface ThirdLevelObject : NSObject <AnotherObjectDelegate>
@end

@implementation ThirdLevelObject
-(void)someMethodWithObject:(id)object {
    // Finally it's here
}
@end

我使用这种类设计是为了防止使用长指针链,例如:

anotherObject.delegate = baseObject.secondLevelObject.thirdLevelObject;

并防止我的类有太多弱/分配引用,当您有多个符合多个协议的对象时,这些引用可能难以调试。

其中一个缺点是我必须在每个用作“代理”来转发消息的类中添加那些类似于样板代码的协议实现。即使 - 在我的情况下 - 这更容易阅读和调试。

所以我问自己是否有更简单的方法来做到这一点。我也这样做是为了防止我的代码调用

if ([delegate respondsToSelector:@selector(someMethod)]
    [delegate someMethod];

这里有什么可以帮助我的 Objective-C 运行时函数吗?

【问题讨论】:

    标签: objective-c cocoa protocols


    【解决方案1】:

    最简单的就是实现forwardingTargetForSelector:。当你收到你没有回复的消息时,这个方法会被调用,无论它返回什么对象都会被发送消息。

    例如:

    @implementation SecondLevelObject
    - (id)forwardingTargetForSelector:(SEL)aSelector {
        // Often you would actually check the selector here
        return self.thirdLevelObject;
    }
    @end
    

    问题是现在SecondLevelObject 似乎不符合协议,这将产生警告。您可以使用编译指示抑制该警告(因为您确实符合协议):

    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wprotocol"
    @implementation SecondLevelObject
    ...
    @end
    #pragma clang diagnostic pop
    

    不过,这会关闭整个对象的协议检查,因此您需要非常小心。在大多数情况下,我发现只编写转发代码会更容易和更清晰。如果它很多,它有时表示不同的设计问题。也许 LevelThreeObject 真的应该是委托本身,或者像通知或 KVO 这样的松散系统会更好。但是转发仍然很合理,这是一种需要考虑的技术。

    【讨论】:

    • 我测试了不同的设计,但转发似乎是最透明和最高效的,因为我经常转发每秒被多次调用的方法。我不太确定转发是否很常见,但现在我确定了!谢谢!
    猜你喜欢
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多