EDIT: As sunshinejr pointed out here, this has been fixed and will be released together with the next Xcode/Swift version.
I've seen a lot of weird behaviour after updating Xcode 10.1 to Xcode 10.2, both with Swift 4 and Swift 5 codebases.
One of the problems is that on one ViewController the ScrollView delegate methods are no longer called. The simplified view hierarchy is as follows:
| ScrollView (ParentScrollView)
| -- Stack View
| ---- ScrollView (ChildScrollView)
| ---- ScrollView (ChildScrollView)
| ---- ScrollView (ChildScrollView)
It acts as a view with several pages: ParentScrollView can be scrolled horizontally, the ChildScrollViews vertically.
The ViewController is the delegate of all Scrollviews (set in Storyboard), but the delegate methods (like scrollViewDidEndDecelerating) are not called when scrolling any of the views (ParentScrollView or ChildScrollView). The base class of ViewController conforms to UIScrollViewDelegate.
I have tried setting the delegates in code, other than that I have no idea what I could be doing wrong. The conversion did not change any code in the class, but everything worked well before updating. I also couldn't find any changes to gestures, delegates or ScrollViews in general in the Swift 5 Release Notes.
This seems to be a bug with the Swift 5 compiler. Additionally, sometimes it does work, sometimes it doesn't - all without changing any code or project settings.
Why does this no longer work? Has anyone else experienced similar behaviour?
EDIT: As sunshinejr pointed out here, this has been fixed and will be released together with the next Xcode/Swift version.
I've found the issue, here's how to reproduce it.
class A: UIViewController, UIScrollViewDelegate {
// ...does not implement 'scrollViewDidEndDecelerating'
}
class B: A {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// Will not be called!
}
}
What does work:
class A: UIViewController, UIScrollViewDelegate {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// Probably empty
}
}
class B: A {
override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// Will be called!
}
}
The compiler seems to think that a delegate method is not implemented if the base class did not implement it. If only the child class implements it, it can't find it.
I still can't explain why this behaviour changed with Swift 5, but at least I've found a solution. Maybe someone can give further insights?
Looks like this issue existed back in 2016 as well and was fixed at one point: https://bugs.swift.org/browse/SR-2919
We ran into this with a UITextViewDelegate
Another workaround is to add the @objc tag to the method in the superclass