Reputation: 443
I'm debugging a library that implements a UIScrollViewDelegate
proxy (essentially) like:
class ScrollViewDelegateProxy: NSObject, UIScrollViewDelegate {
private weak var realDelegate: UIScrollViewDelegate?
init(scrollView: UIScrollView) {
super.init()
self.realDelegate = scrollView.delegate
scrollView.delegate = self
}
// MARK: - UIScrollViewDelegate
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Do something...
realDelegate?.scrollViewDidScroll?(scrollView)
}
// Other scroll delegate methods...
// MARK: - Method Forwarding
override func responds(to aSelector: Selector!) -> Bool {
if let realDelegate {
realDelegate.responds(to: aSelector)
} else {
super.responds(to: aSelector)
}
}
override func forwardingTarget(for aSelector: Selector!) -> Any? {
if let realDelegate, realDelegate.responds(to: aSelector) {
realDelegate
} else {
super.forwardingTarget(for: aSelector)
}
}
}
The method forwarding is implemented in case the proxy is sent messages outside of UIScrollViewDelegate
. E.g. if the scrollView were a UITableView
, then the delegate
property would be a UITableViewDelegate
with more methods that are not supported by this proxy. In that case, it should just pass it on.
Because my use case is a UITableView
. I've found that this can crash (not always) with the error message:
'NSInvalidArgumentException', reason: '-[SomeLibrary.ScrollViewDelegateProxy tableView:viewForHeaderInSection:]: unrecognized selector sent to instance'
I think this is because:
responds(to:)
returns true
for a selector while the realDelegate
is in memoryrealDelegate
deallocatesforwardingTarget(for:)
is called later with that selector, but it is not implemented on the proxyI saw this blog post but wasn't sure what the Swift equivalent was.
Is using a weak
property like this with method forwarding simply unsafe?
And what might a safe implementation look like?
Upvotes: 0
Views: 26