top of page
  • Writer's pictureJennifer Eve Vega

SwiftUI: Screen.body.getter crash on iOS 16.0

We recently released an enhancement of one of our features and I was monitoring our crash logs of this new release, everything seems to be going well, until I saw our app hit below target. How bad is it?


Crash Report

Of more than 100k+ sessions, 9 users were affected. When it comes to percentage, it seems really small, right? But these users have reported this crash 200x for the last 3 days. They were very insistent and the fact that they kept trying to use our app means they very much want to use our app - and we heard them!


They are all using iOS 16.0, and an iPhoneXR. It's the first time I got 100% issue on a specific iOS version and device.


What was the crash?

EXC_BAD_ACCESS __swift_instantiateConcreteTypeFromMangledName

Attempted to dereference null pointer.


EXC_BAD_ACCESS __swift_instantiateConcreteTypeFromMangledName Attempted to dereference null pointer.

This new SwiftUI screen crashed on its body. I could not replicate it on the simulator (iOS 16.0 and iPhone XR), so it was difficult for me to confirm what exactly caused it.


I looked for this issue online, and found a related forum/thread which was happening on Xcode 13.2. I am still hesitant because other people said that issue has been resolved on the next Xcode 13.3 beta release. But a part of me thought it might be related because in the thread, it mentioned that it happens in our variable body, where we have:

if #available(16.0) {
	// Do This
} else {
	// Do That
}

And someone also posted a fix that he confirms will work on iOS 14. And the solution was to create a View Modifier!


Solutions to fix SwiftUI body.getter crash

Solution #1: Use a View Modifier

So instead of doing an if #available() inside the body variable, you pull that code out and put it in a View Modifier.


Example:

As we all might know already, SwiftUI is still quite new, and there are some variables/methods only available to specific iOS versions. So for my problem, instead of doing this:

var body: some View {
	if #available(iOS 16.0, *) {
		// code only available on iOS 16 and up	
	} else {
		// code for older iOS version
	}
}

We can do this:

struct HideNavigationViewModifier: ViewModifier {
	func body(content: Content) -> some View {
		if #available(iOS 16.0, *) {
			// code only available on iOS 16 and up	
		} else {
			// code for older iOS version
		}
	}
}
extension View {
	func hideNavigationView() -> some View {
		modifier(HideNavigationViewModifier())
	}
}

And in our body

var body: some View {
	contentView
		.hideNavigationView()
}

Solution #2: Check if using old iOS version code works for old/new iOS versions

Apart from this solution, there is another option, and that is to check if using the code for older iOS versions has the same effect when used on the new iOS versions. And if that is the case, you might just not need to create a ViewModifier, instead, simply remove the if #available() in your code and just use the code for older iOS version.

var body: some View {
	if #available(iOS 16.0, *) {
		// code only available on iOS 16 and up	
	} else {
		// code for older iOS version
	}
}

Remember to check it well to make sure the desired outcome is the same for old or newer versions.


Conclusion

I think this issue does not only happen on iOS 16, it could happen to any iOS versions. Just remember that if you encounter the same issue as what we had, you can fix it by using a View Modifier, or you might just not need the if #available() if the older code works for old/new iOS versions.

コメント


bottom of page