Skip to content

Commit

Permalink
DebugViewModel: fixed runtime crash on iOS < 16 (#3139)
Browse files Browse the repository at this point in the history
Fixes RevenueCat/purchases-capacitor#100 and
https://app.circleci.com/pipelines/github/RevenueCat/purchases-ios/14093/workflows/b3f8d001-6f39-40db-a5c5-00fc37d0211e/jobs/105838

```
Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   ???                           	               0x0 ???
1   libswiftCore.dylib            	       0x18f9b8cf8 swift_getSingletonMetadata + 956
2   RevenueCat                    	       0x107f42de4 type metadata accessor for DebugViewModel + 64
3   libobjc.A.dylib               	       0x18017d938 realizeClassMaybeSwiftMaybeRelock(objc_class*, mutex_tt<false>&, bool) + 116
4   libobjc.A.dylib               	       0x180184eb0 realizeAllClasses() + 168
5   libobjc.A.dylib               	       0x180187b3c objc_copyClassList + 36
6   XCTestCore                    	       0x10532fcb0 +[XCTestCase(RuntimeUtilities) _allSubclasses] + 36
7   XCTestCore                    	       0x10532fdb8 +[XCTestCase(RuntimeUtilities) allSubclasses] + 16
```

Both `XCTest` (to load tests at runtime) and `Capacitor` use
`objc_getClassList`. That's broken before iOS 16 and will try to load
the metadata for `DebugViewModel` even though it's not `@available`.
A similar issue has been reported before:
https://openradar.appspot.com/radar?id=4970535809187840 /
swiftlang/swift#58099

This adds a layer of indirection so loading `DebugViewModel` at runtime
doesn't require the metadata for `NavigationPath`.
  • Loading branch information
NachoSoto authored Sep 5, 2023
1 parent 102cbe7 commit 0608e97
Showing 1 changed file with 10 additions and 1 deletion.
11 changes: 10 additions & 1 deletion Sources/Support/DebugUI/DebugViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,17 @@ final class DebugViewModel: ObservableObject {
var currentAppUserID: String?
#endif

// We can't directly store instances of `NavigationPath`, since that causes runtime crashes when
// loading this type in iOS <= 15, even with @available checks correctly in place.
// See https://openradar.appspot.com/radar?id=4970535809187840 / https://github.com/apple/swift/issues/58099
@Published
var navigationPath = NavigationPath()
private var _navigationPath: Any = NavigationPath()

var navigationPath: NavigationPath {
// swiftlint:disable:next force_cast
get { return self._navigationPath as! NavigationPath }
set { self._navigationPath = newValue }
}

func load() async {
self.configuration = .loaded(.create())
Expand Down

0 comments on commit 0608e97

Please sign in to comment.