本物のデリゲートへの隠しポインターを保存し、すべての着信メッセージをそこに転送するという H2CO3 の提案に基づいて、私は次の解決策を思いつきました。
setDelegate:
メソッドに渡される「実際の」デリゲートへの参照を格納するプライベート デリゲート変数を宣言します。
@interface BFWaveScrollView ()
@property (nonatomic, weak) id<UIScrollViewDelegate> ownDelegate;
@end
デリゲートを self に設定して、スクロール イベントについて通知を受けます。を使用super
して、元のsetDelegate:
実装が呼び出され、変更されたものではありません。
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[super setDelegate:self];
}
return self;
}
setDelegate:
「実際の」デリゲートへの参照を保存するためにオーバーライドします。
- (void)setDelegate:(id<UIScrollViewDelegate>)delegate {
_ownDelegate = delegate;
}
UIScrollViewがデリゲートのメソッドを呼び出そうとすると、最初にデリゲートかどうかがチェックされますrespondsToSelector:
。セレクターがプロトコルの一部である場合は、これを実際のデリゲートに転送する必要がありUIScrollViewDelegate
ます (忘れないでください#import <objc/runtime.h>
)。
- (BOOL)selectorIsScrollViewDelegateMethod:(SEL)selector {
Protocol *protocol = objc_getProtocol("UIScrollViewDelegate");
struct objc_method_description description = protocol_getMethodDescription(
protocol, selector, NO, YES);
return (description.name != NULL);
}
- (BOOL)respondsToSelector:(SEL)selector {
if ([self selectorIsScrollViewDelegateMethod:selector]) {
return [_ownDelegate respondsToSelector:selector] ||
[super respondsToSelector:selector];
}
return [super respondsToSelector:selector];
}
最後に、サブクラスに実装されていないすべてのデリゲート メソッドを実際のデリゲートに転送します。
- (id)forwardingTargetForSelector:(SEL)selector {
if ([self selectorIsScrollViewDelegateMethod:selector]) {
return _ownDelegate;
}
return [super forwardingTargetForSelector:selector];
}
サブクラスによって実装されるデリゲート メソッドを手動で転送することを忘れないでください。