I've run into a dead end right now. For quick context, I've been using some hidden SwiftUI APIs which are public but prefixed with an underscore. I'm fully aware that those APIs are hidden for good reasons, that's not my issue with them though. Those APIs work as expected, but there's a really strange catch to it.
SwiftUI has hidden APIs like _ScrollView
, _PagingView
and some underlying structures such as _ScrollableLayout
protocol etc.
The _PagingView
, constructs _ScrollView<_ScrollableLayoutView<some Collection, PagingLayout>>
. The PagingLayout
type is private to the framework but it's known to conform to the _ScrollableLayout
protocol. The _PagingView
can be constructed and used just fine with an iOS 15 simulator.
However this issue starts when we implement and call a custom type which also conforms to the _ScrollableLayout
protocol.
This minimal example can reproduce the issue:
import SwiftUI
@main
struct YOUR_APPS_NAME: App {
var body: some Scene {
WindowGroup {
let views: [Color] = [] // empty, not relevant
// the subscript comes protocol and constructs
// _ScrollView<_ScrollableLayoutView<[Color], CustomLayout>>
CustomLayout()[views]
}
}
}
struct CustomLayout: _ScrollableLayout {
func update(state: inout (), proxy: inout _ScrollableLayoutProxy) {
// can be empty for the test, not relevant
}
// no effect if uncommented
// func decelerationTarget(contentOffset: CGPoint, originalContentOffset: CGPoint, velocity: _Velocity<CGSize>, size: CGSize) -> CGPoint? {
// nil
// }
}
The iOS 15.X simulators all crash (tested only with 15.0 and 15.5). iOS 16.0 runs the application just fine.
The crash:
dyld[22806]: Symbol not found: _$s7SwiftUI17_ScrollableLayoutP18decelerationTarget13contentOffset015originalContentH08velocity4sizeSo7CGPointVSgAJ_AjA9_VelocityVySo6CGSizeVAOSQ12CoreGraphicsyHCg_GAOtFTq
Referenced from: /Users/admin/Library/Developer/CoreSimulator/Devices/098D24BA-E32C-49FB-BD04-2DBD1CB0584C/data/Containers/Bundle/Application/A249D7E6-0CFF-45A4-AD7B-521E80405ED8/ScrollTester.app/ScrollTester
Expected in: /Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 15.0.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/SwiftUI.framework/SwiftUI
When demangling the above we get:
method descriptor for
SwiftUI._ScrollableLayout.decelerationTarget(contentOffset: __C.CGPoint, originalContentOffset: __C.CGPoint, velocity: SwiftUI._Velocity<__C.CGSize>, size: __C.CGSize) -> __C.CGPoint?
This particular protocol function exists since iOS 13, I double checked iOS 13 and 15.5 .swiftinterface
files from the system modules.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol _ScrollableLayout : SwiftUI.Animatable {
...
func decelerationTarget(contentOffset: CoreGraphics.CGPoint, originalContentOffset: CoreGraphics.CGPoint, velocity: SwiftUI._Velocity<CoreGraphics.CGSize>, size: CoreGraphics.CGSize) -> CoreGraphics.CGPoint?
}
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension SwiftUI._ScrollableLayout {
public func decelerationTarget(contentOffset: CoreGraphics.CGPoint, originalContentOffset: CoreGraphics.CGPoint, velocity: SwiftUI._Velocity<CoreGraphics.CGSize>, size: CoreGraphics.CGSize) -> CoreGraphics.CGPoint?
}
I sent the example to someone with an iPhone running iOS 15.x to test if the issue is present on a real device, and it also crashes there. I'm running out of ideas. Is there anything I can do about it? I really have to use that custom layout type which also implements the decelerationTarget
method.