-
Notifications
You must be signed in to change notification settings - Fork 99
Description
Describe the bug
Memory deallocation issue in the OverlayScrollViewDelegateProxy.
Environnement
- Device: iPhone 16 Pro Simulator
- OS: iOS 18.2
- OverlayContainer Version: aa7bd20
Description
As you know, the proxy sets itself as the UIScrollViewDelegate:
scrollView.delegate = selfFor our use case, the scrollView is a UITableView; so the delegate is a UITableViewDelegate.
As a result, it will be sent messages like tableView:viewForHeaderInSection:.
The framework does consider this, as we see in the following code to forward on other messages:
override func responds(to aSelector: Selector!) -> Bool {
let originalDelegateRespondsToSelector = originalDelegate?.responds(to: aSelector) ?? false
return super.responds(to: aSelector) || originalDelegateRespondsToSelector
}
override func forwardingTarget(for aSelector: Selector!) -> Any? {
if originalDelegate?.responds(to: aSelector) == true {
return originalDelegate
} else {
return super.forwardingTarget(for: aSelector)
}
}where:
private weak var originalDelegate: UIScrollViewDelegate?But there is a bug here, a few:
- In ARC in Swift: Basics and Beyond, we see how Swift is non-lexical. Above, in
forwardingTarget(for:),originalDelegatemay respond to a selector and be deallocated when it is returned (because it isweak) originalDelegatemay causeresponds(to:)to returntrue, but have been deallocated inforwardingTarget(for:)
The second is why we are seeing crashes in our app.
Just before the crash, forwardingTarget(for:) is called with selector tableView:viewForHeaderInSection: and the originalDelegate is nil.
Returning nil for this scenario in forwardingTarget(for:) does not stop the invocation.
So we are experiencing the following crash in our app:
'NSInvalidArgumentException', reason: '-[OverlayContainer.OverlayScrollViewDelegateProxy tableView:viewForHeaderInSection:]: unrecognized selector sent to instance'
It looks to me like you might have done the same as this SO answer.
Currently, I don't think it's a correct implementation of a proxy in Swift for weak references.