.navigationBarTitleDisplayMode(.inline) crashes Xcode preview - xcode

I am consistently coming across this issue whenever I use .navigationBarTitleDisplayMode(.inline). Is there a problematic use of this method, or is there something incorrect about my code ?
How to reproduce error:
In the preview, hit the "list.bullet.rectangle.fill" and dismiss the dialog. Do it a second time and now Xcode crashes the Preview.
Xcode Version 14.2 (14C18)
import SwiftUI
struct PDFTableContentsView: View {
var body: some View {
Text("PDF Table Contents View")
.bold()
.underline()
}
}
struct PDFContentView: View {
#State private var showContents: Bool = false
var body: some View {
VStack {
Text(/*#START_MENU_TOKEN#*/"Hello, World!"/*#END_MENU_TOKEN#*/)
}
.navigationTitle("PDF Title")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
showContents.toggle()
} label: {
Image(systemName: "list.bullet.rectangle.fill")
}
}
}
.sheet(isPresented: $showContents) {
PDFTableContentsView()
}
}
}
struct PDFContentView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
PDFContentView()
}
}
}

Related

SwiftUI for macOS - trigger sheet .onDismiss problem

In a multiplatform app I'm showing a sheet to collect a small amount of user input. On iOS, when the sheet is dismissed, the relevant .onDismiss method is called but not on macOS.
I've read that having the .onDismiss in the List can cause problems so I've attached it to the button itself with no improvement. I've also tried passing the isPresented binding through and toggling that within the sheet itself to dismiss, but again with no success.
I am employing a NavigationView but removing that makes no difference. The following simplified example demonstrates my problem. Any ideas? Should I even be using a sheet for this purpose on macOS?
I just want to make clear that I have no problem closing the sheet. The other questions I found were regarding problems closing the sheet - I can do that fine.
import SwiftUI
#main
struct SheetTestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
var body: some View {
NavigationView {
ListView()
}
}
}
The List view.
struct ListView: View {
#State private var isPresented: Bool = false
var body: some View {
VStack {
Text("Patterns").font(.title)
Button(action: {
isPresented = true
}, label: {
Text("Add")
})
.sheet(isPresented: $isPresented, onDismiss: {
doSomethingAfter()
}) {
TestSheetView()
}
List {
Text("Bingo")
Text("Bongo")
Text("Banjo")
}
.onAppear(perform: {
doSomethingBefore()
})
}
}
func doSomethingBefore() {
print("Johnny")
}
func doSomethingAfter() {
print("Cash")
}
}
This is the sheet view.
struct TestSheetView: View {
#Environment(\.presentationMode) var presentationMode
#State private var name = ""
var body: some View {
Form {
TextField("Enter name", text: $name)
.padding()
HStack {
Spacer()
Button("Save") {
presentationMode.wrappedValue.dismiss()
}
Spacer()
}
}
.frame(minWidth: 300, minHeight: 300)
.navigationTitle("Jedward")
}
}
Bad issue.. you are right. OnDismiss is not called. Here is a workaround with Proxybinding
var body: some View {
VStack {
Text("Patterns").font(.title)
Button(action: {
isPresented = true
}, label: {
Text("Add")
})
List {
Text("Bingo")
Text("Bongo")
Text("Banjo")
}
.onAppear(perform: {
doSomethingBefore()
})
}
.sheet(isPresented: Binding<Bool>(
get: {
isPresented
}, set: {
isPresented = $0
if !$0 {
doSomethingAfter()
}
})) {
TestSheetView()
}
}

SwiftUI macOS right sidebar inspector

I have a document-based SwiftUI app. I'd like to make a inspector sidebar like the one in Xcode.
Starting with Xcode's Document App template, I tried the following:
struct ContentView: View {
#Binding var document: DocumentTestDocument
#State var showInspector = true
var body: some View {
HSplitView {
TextEditor(text: $document.text)
if showInspector {
Text("Inspector")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
.toolbar {
Button(action: { showInspector.toggle() }) {
Label("Toggle Inspector", systemImage: "sidebar.right")
}
}
}
}
Which yielded:
How can I extend the right sidebar to full height like in Xcode?
NavigationView works for left-side sidebars, but I'm not sure how to do it for right-side sidebars.
Here is some stripped down code that I have used in the past. It has the look and feel that you want.
It uses a NavigationView with .navigationViewStyle(.columns) with essentially three panes. Also, the HiddenTitleBarWindowStyle() is important.
The first (navigation) pane is never given any width because the second (Detail) pane is always given all of the width when there is no Inspector, or all of the width less the Inspector's width when it's present. The ToolBar needs to be broken up and have its contents placed differently depending on whether the Inspector is present or not.
#main
struct DocumentTestDocumentApp: App {
var body: some Scene {
DocumentGroup(newDocument: DocumentTestDocument()) { file in
ContentView(document: file.$document)
}
.windowStyle(HiddenTitleBarWindowStyle())
}
}
struct ContentView: View {
#Binding var document: DocumentTestDocument
#State var showInspector = true
var body: some View {
GeometryReader { window in
if showInspector {
NavigationView {
TextEditor(text: $document.text)
.frame(minWidth: showInspector ? window.size.width - 200.0 : window.size.width)
.toolbar {
LeftToolBarItems(showInspector: $showInspector)
}
Inspector()
.toolbar {
RightToolBarItems(showInspector: $showInspector)
}
}
.navigationViewStyle(.columns)
} else {
NavigationView {
TextEditor(text: $document.text)
.frame(width: window.size.width)
.toolbar {
LeftToolBarItems(showInspector: $showInspector)
RightToolBarItems(showInspector: $showInspector)
}
}
.navigationViewStyle(.columns)
}
}
}
}
struct LeftToolBarItems: ToolbarContent {
#Binding var showInspector: Bool
var body: some ToolbarContent {
ToolbarItem(content: { Text("test left toolbar stuff") } )
}
}
struct RightToolBarItems: ToolbarContent {
#Binding var showInspector: Bool
var body: some ToolbarContent {
ToolbarItem(content: { Spacer() } )
ToolbarItem(placement: .primaryAction) {
Button(action: { showInspector.toggle() }) {
Label("Toggle Inspector", systemImage: "sidebar.right")
}
}
}
}
struct Inspector: View {
var body: some View {
VStack {
Text("Inspector Top")
Spacer()
Text("Bottom")
}
}
}

SwiftUI: Perpetual Diagnostic Error When Building NavigationBar

I'm new to SwiftUI, and I'm trying to build this nav bar using Xcode 12.4:
Here is the entirety of my view:
struct PreferencesView: View {
var body: some View {
NavigationView {
ZStack {
//Background Color
Color("DosDark")
.edgesIgnoringSafeArea(.all)
Text("Hey.")
//Nav bar styles
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
VStack {
Text("Preferences")
.navBarTitleDark()
}
}
}
.navigationBarItems(
leading: NavClose(), //<-- This is where the trouble starts
trailing: NavAbout()
)
}
}
}
}
struct NavClose: View {
var body: some View { //<-- Inexplicable error here
Button(action: {
print("Close...")
}){
Image("close-blue")
}
}
}
struct NavAbout: View {
var body: some View {
Button(action: {
print("Show about stuff...")
}) {
Image("about-blue")
}
}
}
I can get the title to render okay, but as soon as I add the .navigationBarItems bit, I see an error endlessly on my struct that I'm trying to pull in:
When I try putting the Button directly in .navigationBarItems (without using an external struct) I still see the error on that line:
Failed to produce diagnostic for expression; please file a bug report
Am I doing something wrong? Is there a way to make Xcode give me a real error message?
Works fine with Xcode 12.1 / iOS 14.1, but .navigationBarItems was deprecated for the preference of toolbar and probably you have newer version where they are already conflicted.
The solution is to use only toolbar with corresponding placements, like
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
NavClose()
}
ToolbarItem(placement: .navigationBarTrailing) {
NavAbout()
}
ToolbarItem(placement: .principal) {
VStack {
Text("Preferences")
.navBarTitleDark()
}
}
}

SwiftUI: App crashes when resizing ScrollView with 3 TextField inside HStack on macOS

Here is the full example:
import SwiftUI
struct ContentView: View {
var body: some View {
ScrollView {
HStack {
ForEach(1...3, id: \.self) { idx in
TextField("", text: .constant("text \(idx)"))
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Xcode version: 11.5
When I am resizing window app crashes with the following exception:
Assertion failure in -[_TtC7SwiftUIP33_A874FC5B9DB530D4375C25AE2AA39DF215HostingClipView setBoundsOrigin:], /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/AppKit/AppKit-1894.40.150/AppKit.subproj/NSView.m:5646
Am I doing something wrong?
Update:
When I change number of TextFields to 4 resizing works fine.
Here is workaround. Fixed variant tested with Xcode 11.4 / macOS 10.15.4
struct CrashedContentView: View {
var body: some View {
GeometryReader { gp in
ScrollView {
HStack {
ForEach(1...3, id: \.self) { idx in
TextField("", text: .constant("text \(idx)"))
}
}.frame(width: gp.size.width)
}
}
}
}

Why cant I see my for Each loop in the preview view in XCode

I am making a to do list to learn about Core data. I noticed when I add a ForEach loop to read my core data entries, it stops loading the view and the app crashes. If I replace the ForEach loop with a Text("Hi"), it all works. However the app runs perfectly in simulator.
import SwiftUI
struct ContentView: View {
#Environment(\.managedObjectContext) var managedObjectContext
#FetchRequest(fetchRequest: ToDoItem.getAllToDo()) var toDoItems:FetchedResults<ToDoItem>
#State private var newTodoItem = ""
#State private var selection = 0
var body: some View {
NavigationView {
List {
Section (header: Text("Whats... next")) {
HStack{
TextField("New Item", text: self.$newTodoItem)
Button(action: {
let toDoItem = ToDoItem(context: self.managedObjectContext)
toDoItem.title = self.newTodoItem
toDoItem.createdAt = Date()
do {
try self.managedObjectContext.save()
}catch {
print(error)
}
self.newTodoItem = ""
}){
Image(systemName: "plus.circle.fill")
.foregroundColor(.green)
.imageScale(.large)
}
}
}.font(.headline)
Section(header: Text("To Do's")){
ForEach(self.toDoItems) {todoItem in
HStack{
VStack(alignment: .leading){
Text(todoItem.title!)
.font(.headline)
Text("\(todoItem.createdAt!)")
.font(.caption)
}
}
}.onDelete {indexSet in
let deleteItem = self.toDoItems[indexSet.first!]
self.managedObjectContext.delete(deleteItem)
do {
try self.managedObjectContext.save()
}catch {
print(error)
}
}
}
}
.navigationBarTitle(Text("My List"))
.navigationBarItems(trailing: EditButton())
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Any idea what the issue is?

Resources