Hello @ruzambo,
I copied your app into a new Xcode project and it didn't encounter the crash you specified. I can click remove button three times and it removes the last element. If I click the remove button one more time (forth time), it does crash because itemsCopy.removeLast() is being called on an empty collection.
I am also on Big Sur (20D5029f) and Xcode (20D5029f). Is your target iOS?
Post
Replies
Boosts
Views
Activity
I tried to recreate the scenario that you presented. I wasn't entirely clear on what type of scenario you have. Below is the following that I was able to piece together.
struct ViewBB: View {
var body: some View {
Text("ViewBB")
}
}
struct ViewB: View {
@Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
ViewBB()
.navigationBarTitle("View B", displayMode: .inline)
.navigationBarItems(leading: Button("Cancel") {
self.presentationMode.wrappedValue.dismiss()
})
}
}
}
struct ContentView: View {
@State private var isPresetend: Bool = false
var body: some View {
VStack {
Button(action: {
self.isPresetend.toggle()
}, label: { Text("Change view") })
.sheet(isPresented: $isPresetend, content: { ViewB() })
.navigationBarTitle("View A", displayMode: .inline)
}
}
}
Potentially this is already solved in an update to SwiftUI, but with the above code, the view does get dismissed via presentationMode. Unsure if this is entirely what the post was referring to, but if you could provide more of the logic/flow of what is happening to encounter this unexpected behavior, that would be appreciated.
The first question I have is about that Binding. Since this is the ContentView (presumably the first view of your app), what State is it being bound to? I didn't know, so based on the fact that it was a bind, I rewrote it to include another view (compacted the code to make it smaller):
struct OtherView: View {
@Binding var x1: Int
@State var x2: Int = 0
var body: some View {
VStack {
Button(action: {
withAnimation { x1 += 1; x2 += 2 }
}, label: { Text("Increment").padding() })
Text("Total: \(total)")
}
}
var total: Int { print("\(x1) + \(x2) = \(x1 + x2)"); return x1 + x2 }
}
struct ContentView: View {
@State private var value: Int = 0
var body: some View {
OtherView(x1: $value)
}
}
With this, it doesn't update the view twice, and only prints, 1 + 2 = 3.
In regards to your question about using a Binding and a State, this is possible (as shown above), but I would need to see your other view that the Binding is being connected to. If this doesn't answer your question, can you please expand/explain why you are using a Binding without binding it to something.
I think this might be fixed in Xcode 12.3 Beta. I ran the code in the live preview and in the simulator, and I am able to hit the close button on the upper right corner to close the ColorPicker and have the selected color outside that view.
@Tact,
There wasn't much provided except for a few pieces of code, so it is hard to determine the exact flow of your application, so I took some liberty in piecing together what you might have. I have also never tried to implement this style of application, so I decided to try my best to solve it; learned some new things! Below is what I got working:
class Store: ObservableObject {
@Published var backgroundColor: Color
init() {
self.backgroundColor = .green
}
}
struct ChangeBackgroundColor: View {
@Binding var backgroundColor: Color
var body: some View {
ZStack {
VStack {
Button(action: { self.backgroundColor = .black }, label: { Text("Black") })
Button(action: { self.backgroundColor = .green }, label: { Text("Green") })
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.background(backgroundColor).edgesIgnoringSafeArea(.all)
}
}
struct ContentView: View {
@ObservedObject var store: Store = Store()
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: ChangeBackgroundColor(backgroundColor: $store.backgroundColor)) {
Text("Pick Background Color")
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.background(store.backgroundColor).edgesIgnoringSafeArea(.all)
}
}
}
I ran into the issue that others have encountered when trying to set the background color that involves the NavigationView. It appears that the the underline View either doesn't have/use the dimensions of the screen, so either using GeometryReader or .infinity should get a desired effect of turning the whole background color via just SwiftUI. Hopefully this will get you going and understand the relationship on how to pass values around different views.
If you don't plan on using NavigationView or some of the other views that have issues with .background, you can easily use Color() example you provided.
I don't know if it's a bug or just undefined behavior. It looks like it always displays a blank toolbar when isFavorite gets updated. My guess is that SwiftUI don't know which one should be on top (or it renders the ContentView toolbar, but it doesn't show the text because it doesn't exist in DetailView?). If you comment out the Image(systemName: isFavorite ? "star.fill" : "star"), the ContentView doesn't get rendered again, so it doesn't change the toolbar, but it seems that when DetailView propagates an update to ContentView is clashes over what ToolbarItem(placement: .bottomBar) to use.
I tried a couple different solutions, conditional in the ToolbarItem, making an observable object, settings views with onAppear and onDisappear, but non of them resulted in a work around for this problem.
Either it it s bug, or this type of behavior isn't supposed to happen in SwiftUI. Do you have an example of an App that is dynamically changing the toolbar based on the view in SwiftUI?
@richiwalt,
Most of the current issues can be fixed with adding the frame modifier just inside the body view which fixes GeometryReader and ForEach. It is a temporary fix to get the program running in the app again. In the next update to Playgrounds (or potentially a mini update) will see this fixed (hopefully).
I do not know if Apple engineers monitor this form. Yes, there is a place where you can submit feedback to Apple. On all the latest versions of MacOS, iOS, and iPadOS, there is the Feedback app (Feedback Assistant on MacOS). Here you can submit errors, bugs, or feedback to Apple. I would fully suggestion entering feedback to send to Apple, so they can get a better understanding of what is occurring.
@Enevold,
I looked at what you have, and it did confirm what I was thinking that you are trying to use global variables. I would suggest refactoring your code and look into some tutorials on how SwiftUI handles the movement of data. Below I have modified your program some:
struct ContentView: View {
@State private var servIp: String = "192.168.0.196"
let port: Int = 8000
let cmd: String = "xmlcommand"
var body: some View {
VStack(alignment: .leading) {
HStack {
Text("Enter Control IP")
TextField("Enter Control IP...", text: $servIp)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
Button(action: {
sendHttpPostDesktops()
}, label: {
Text("Desktops")
}).buttonStyle(PlainButtonStyle())
}
}
func sendHttpPostDesktops() {
print("servIP = \(servIp)")
}
}
I removed your ServerIPInput struct because I didn't see where you called this view ContentView. In the example above, servIp will be whatever the user enters into the textfield; otherwise, it will be keep the initial value of 192.168.0.196. If you want another struct view, you should look into how to bind to a state variable to create a connection for passing data between views. My final suggestion would be looking into making an object that contains all the server logic. For example, you can make an observable object that contains the sendHttpPostDesktops function. This way, it separates your view and data logic.
@Enevold,
Your code does work and CTRLIP would contain the text of whatever the user entered in the textfield. Based on what information you have given, you seem to be treating CTRLIP as a global variable. You mention that you have this line in another struct:
let servIp = "$CTRLIP"
If this line is in another struct, "$CTRLIP" is just a string nothing to do with the State variable in the ServerIPInput view. What OOPer was referring to was posting that struct that contains the servIp variable to see why it isn't connected.
It is unclear to see how your struct that contains servIp is getting the value from the ServerIPInput view. If ServerIPInput is a child view of this struct that contains servIp, you can turn CTRLIP into a Binding variable which will create the connection for data to transfer back to the parent view, but the parent view would need the State.
That is interesting @Yoko_Ono. I made the project for MacOS, and didSet does get called when I hit CMD + Z (on both undo and redo). Although, it seems very inconsistent what it undos. Either it will just do one work or everything that was done in the document.
This was able to be fixed via added the frame modifier to the list view.
List {
ForEach( fruitList ) { fruit in
HStack {
Text("\(fruit.emoji)")
Text("\(fruit.name)")
}
.font(.title)
}
}.frame(width: 500, height: 500)
I would assume based on the other question with Abort(), that Abort() is called if it is about to crash, and it seems that the view isn't getting the bounds of the screen in the live view, so it doesn't know how/where to render the view.
@richiwalt,
I answered a different question on the forms and I think the issue is the same. After the update to 3.4, I don't think the screen size of the live view is being registered currently inside the ContentView (or any view) which is leading to unexpected behavior for views that need that information.
struct ContentView: View {
var emojis = "🐿 🐝🦋🐌🐞🐜🐛🦒🐘🦛🦓🦏🐪"
var body: some View {
VStack {
ScrollView(.horizontal) {
HStack {
ForEach( emojis.map { String($0) }, id: \.self ) { emoji in
Text(emoji).font(Font.system(size: 45))
}
}
.padding(.horizontal)
}
Color.yellow.edgesIgnoringSafeArea([.horizontal, .bottom])
}
.frame(width: 500, height: 500)
.background(Color.white)
}
}
If you add the frame modifier it seems to make it work in the meantime. It scrolls left and right without crashing.
I think there is an issue currently where Playgrounds 3.4 GeometryReader isn't registering the screen size for the live view. I added the the frame modifier to the GeometryReader view and this allows it to run in Playgrounds 3.4 and not run into the Abort() issue. I tried to add the frame modifier to ContentView(), but it resulted in the Abort() function being called. Unsure if there is a place to see the logs for Playgrounds to see what causes Abort() to be called.
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
Color.blue.frame(height: geometry.size.height * 0.5)
}.frame(width:500, height: 500)
}
I copied your code it and confirmed that it didn't run in Playgrounds 3.4. If you take out
Color.yellow.edgesIgnoringSafeArea([.horizontal, .bottom])
your code runs as expected. What are you trying to make yellow?
Not the same issue, but it does appear that 3.4 is having some issues. The ForEach loop isn't working as expected, it will iterate through the data, but it doesn't render correctly whatever is in the brackets.
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
/*Text("TEST")*/
ForEach((1...5), id: \.self) { index in
Text("TEST TEST")
}
}
.foregroundColor(Color.green)
.background(Color.red)
}
}
PlaygroundPage.current.setLiveView(ContentView())
When run in the playground, the Text view inside for ForEach loop does not display the text, but the background color does show that the view is there, but the text just doesn't get displayed. When the Text view outside of the ForEach loop is uncommented and ran, an alert appears stating "There was a problem running this playground. Please check your code and try again." I copied over the code to Xcode, and it ran as expected. I'm on the new iPadOS developer beta and playgrounds 3.4.