Reputation: 268245
I need to chain into a UIScrollView
's delegate (it's not in my code and I have no control over it) and handle some of its methods, while passing all events to the previous delegate.
My naïve implementation was this proxy class:
public class ScrollViewProxyDelegate : UIScrollViewDelegate
{
private UIScrollViewDelegate _realDelegate;
public ScrollViewProxyDelegate (UIScrollViewDelegate realDelegate)
{
_realDelegate = realDelegate;
}
public override void DecelerationStarted (UIScrollView scrollView)
{
_realDelegate.DecelerationStarted (scrollView);
}
public override void DecelerationEnded (UIScrollView scrollView)
{
_realDelegate.DecelerationEnded (scrollView);
}
// ...
}
This didn't work out because scrollView.Delegate
I passed to ScrollViewProxyDelegate
constructor turned out to be null
because this particular delegate was in a different class tree. The property I'm after is WeakDelegate
, but it's an NSObject
.
I read this and I'm still confused. I guess I could just call Objective C selectors on this NSObject
in each method but could there be a less verbose way?
I just tried proxying PerformSelector
and RespondsToSelector
but it caused unrecognized selector crashes.
Okay, apparently NSProxy
is what people use for this. Investigating.
Ouch, no NSProxy
in MonoTouch.
I ended up using Key Value Observing to watch my view's contentOffset
. I should've thought about it earlier! Still, I'm curious how to implement a proxy if I ever need it.
What's the easiest way to hook into a view's delegate?
Upvotes: 0
Views: 483
Reputation: 526
I can't quite follow your need for a proxy if the delegate that you're trying to proxy is null, or did you mean that the delegate that you needed to proxy was the scroll view's WeakDelegate?
A WeakDelegate is essentially any NSObject, and any methods that you need to implement must be 'exported' in order for the delegate's owner to be able to invoke them.
[Export("scrollViewDidEndDecelerating:")]
public void MyDecelerationEndedMethod(UIScrollView scrollView)
{
...
}
You can add methods like this onto any NSObject, a view controller for example. If you needed to use a WeakDelegate as the subject of your proxy you'd have to query it to see it if responds to the selector and then perform the selector - which I think is what you were meaning.
However, I don't think you'd be able to write a generic proxy that could handle any delegate because although the proxy gets RespondsToSelector called, it doesn't get PerformSelector called - the selector is sent directly to the proxy and not via PerformSelector. You'd have to write a proxy that implements exactly the same methods as the delegate you want to proxy.
The best I could come up with is something like the following where you'd have to implement each method that the delegate implements.
public class TestProxy : NSObject
{
private NSObject realDelegate;
public TestProxy(NSObject realDelegate)
{
this.realDelegate = realDelegate;
}
public override bool RespondsToSelector(MonoTouch.ObjCRuntime.Selector sel)
{
Console.WriteLine("Query : " + sel.Name);
return this.realDelegate.RespondsToSelector(sel);
}
[Export("tableView:didSelectRowAtIndexPath:")]
public void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
// invoke method on realDelegate either by casting to the correct type or by using
// reflection to find the method that matches the export and pass this method's arguments.
// which way you implement depends on your needs and what you know about the delegate being
// proxied - casting would be much faster than reflection.
}
}
Because you're implementing all the methods that the delegate implements, the RespondsToSelector in redundant and not required.
Upvotes: 3