我有一个非常有趣的崩溃,只有在非常特殊的情况下才会发生。我已经向Apple提交了错误报告,但也许有人在这里遇到了类似的崩溃,知道发生了什么,并且知道解决方法?
可以在https://github.com/kevinrenskers/SwiftUICrash找到显示崩溃的最小项目,但是我还在下面添加了相关代码。该项目具有3个视图:RootView
,DetailsView
和ListView
。 RootView
嵌入DetailsView
或ListView
。
当您按下DetailsView
中的尾随导航栏按钮以切换回ListView
时,就会发生崩溃。该应用程序崩溃,并显示错误“前提条件失败:属性无法设置初始值:71”。
但是,当您使用屏幕中间的Button
切换回ListView
时,不会发生崩溃。而且,当您从背景图片中删除.resizable()
修饰符时,也不会发生崩溃。
此外,如果您将Group
内的NavigationView
更改为RootView
,则该应用程序不会崩溃。遗憾的是,对于我的实际应用程序,这不是一个选择。
import SwiftUI
final class AppStore: ObservableObject {
@Published var showingDetails = true
}
struct RootView: View {
@EnvironmentObject private var store: AppStore
var body: some View {
Group {
if store.showingDetails {
DetailsView()
} else {
ListView()
}
}
}
}
struct DetailsView: View {
@EnvironmentObject private var store: AppStore
var body: some View {
NavigationView {
ZStack {
GeometryReader { geo in
Image("bg")
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
.frame(width: geo.size.width, height: geo.size.height)
}
Button("List") {
self.store.showingDetails = false // <- this works fine
}
.padding(20)
.background(Color.white)
}
.navigationBarTitle(Text("Details"))
.navigationBarItems(trailing: trailingNavigationBarItem)
}
}
private var trailingNavigationBarItem: some View {
Button("List") {
self.store.showingDetails = false // <- this crashes the app!
}
}
}
struct ListView: View {
@EnvironmentObject private var store: AppStore
var body: some View {
NavigationView {
Button("Load details") {
self.store.showingDetails = true
}
.padding(20)
.background(Color.white)
.navigationBarTitle("List")
}
}
}
答案 0 :(得分:3)
尝试用RootView
注释替换@ViewBuilder
中的组:
struct RootView: View {
@EnvironmentObject private var store: AppStore
@ViewBuilder
var body: some View {
if store.showingDetails {
DetailsView()
} else {
ListView()
}
}
}
我不确定那通常有多可靠。过去,我在插入@ViewBuilder
注释中取得了一些成功,但这似乎可以解决嵌套NavigationView
的问题。
答案 1 :(得分:1)
编辑:此替代方法导致iPad的拆分导航视图出现问题。请参阅我的其他答案以获得更好的解决方法。
一种解决方法是将RootView
的{{1}}包装在Group
中,并带有隐藏的导航栏(每个嵌套视图都可能具有自己的导航栏,但并非所有的视图都有一个):
NavigationView
崩溃仍然很奇怪。
答案 2 :(得分:1)
这里是替代解决方法(实际上是在避免发生此问题的可能性),并且经过测试,没有任何不良影响。只是为了考虑...
这个想法不是要删除DetailsView
,而是要使其明确处于非活动状态和隐藏状态。经过Xcode 11.2 / iOS 13.2的测试,没有崩溃。
struct RootView: View {
@EnvironmentObject private var store: AppStore
var body: some View {
ZStack {
ListView()
.zIndex(store.showingDetails ? 0 : 1) // << bring to front
DetailsView()
.opacity(store.showingDetails ? 1 : 0) // << hide
.disabled(!store.showingDetails) // << deactivate
}
}
}
其他视图无变化。
答案 3 :(得分:0)
最后,有效的解决方法是通过UIViewRepresentable使用自定义UIImageView。
struct CustomImage: UIViewRepresentable {
var image: UIImage
var frame: CGRect
func makeUIView(context: Context) -> UIView {
let imageView = UIImageView(frame: frame)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.image = image
let view = UIView(frame: frame)
view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
然后这样使用:
GeometryReader { geo in
CustomImage(image: UIImage(named: "bg")!, frame: CGRect(x: 0, y: 0, width: geo.size.width, height: geo.size.height))
}
.edgesIgnoringSafeArea(.all)
另请参阅https://github.com/kevinrenskers/SwiftUICrash/tree/workarounds/CustomImage。