Post

Replies

Boosts

Views

Activity

New View Instance Uses Old Values
(This post follows on from the solution to Untraceable SIGABRT: precondition failure: attribute failed to set an initial value: <num>)Hopefully one of the last posts I make as I sprint toward this project's end. The issue involves a lot of code that wouldn't be practical to paste here, so I'll do my best to simplify some and leave other bits out completely. If you need the full thing I could maybe email the relevant files but for now hopefully this will do.I have a Dots(_:) view which takes a single parameter, quantity. There is then a chunk of complicated looking code that ultimately randomly places them on screen - this bit has been left out of the post.struct Dots: View { @State private var positions: [DotPosition] = [] let quantity: Int let dot: some View = Circle() .size(width: diam, height: diam) .fill(Color.red) init(_ quantity: Int) { self.quantity = quantity self._positions = State(initialValue: createPositions()) for pos in positions { print(pos)} // <- this is showing that new values ARE being made } var body: some View { GeometryReader { geom in ForEach(self.positions, id: \.self) {position in self.dot .offset(position.offset(maxWidth: geom.size.width, maxHeight: geom.size.height)) // ^ a print statement in here shows iteration over the new values, and then the very first values } } } }The file that could effectively be used as ContentView/root for this problem, again simplified, isstruct SwipableEquation: View { let num: Int var body: some View { VStack { GeometryReader { geo in HStack(spacing: 0) { Group { Dots(self.num) // <- prints show a new instance gets created when exepcted, but the view doesn't change } } } Text(String(num)) // <- this value actively changes as and when expected } } } struct ContentView: View { var nums: [Int] = [2,3,4] @State private var currentEqn = 0 var body: some View { VStack { SwipableEquation(num: nums[currentEqn]) HStack { // Previous Eqn Button(action: { self.currentEqn -= 1 print("\n######### BACK #########") }) { Image(systemName: "chevron.left") VStack { Text("Previous Equation") if currentEqn > 0 { Text(String(nums[currentEqn-1])) } } }.disabled(self.currentEqn == 0) Spacer() // Next eqn Button(action: { self.currentEqn += 1 print("\n######### NEXT #########") }) { VStack { Text("Next Equation") if currentEqn < nums.count-1 { Text(String(nums[currentEqn+1])) } } Image(systemName: "chevron.right") }.disabled(self.currentEqn == nums.count-1) }.padding() } } }
7
1
1.9k
May ’20
Can't Use Dictionary to Store Picker selections?
Note: If the Xcode canvas doesn't show anything in Live Preview, try an actual Simulator - no idea why canvas wasn't working in this demo but not important to the main issue.I have a view with several pickers. Rather than flooding the namespace, I used an array storing the values. This works fine.To improve it, I decided it would be more maintainable to use a dictionary, however, after making the switch, although there are no compile or runtime errors, it appears the picker's selection parameter isn't able to read or write to the dictionary?struct ContentView: View { @State private var data = [ // <- doesn't appear to be used by picker 1 "key1": 0, "key2": 5 ] @State private var indices = [Int](repeating: 0, count: 2) // <- updates fine var body: some View { NavigationView { Form { // Picker 1, doesn't work Picker(selection: $data["key1"], label: Text("dict")) { ForEach(0..<100) { Text(String($0)) // <- shows no value } } // Picker 2, works fine Picker(selection: $indices[0], label: Text("array")) { ForEach(0..<100) { Text(String($0)) } } } } } }
3
0
3.9k
May ’20
Custom Modifier Using Text's underline(_:color:)
I have a custom modifier which is only used on a Text view. I want to include an underline call in it, but get an error. My understanding is that this is because underline is unique to Text views whereas the ViewModifier protocol isn't.Is there a way to specify this?struct activeEquationString: ViewModifier { let termInd: Int @Binding var currentInd: Int func body(content: Content) -> some View { content .underline(currentInd == termInd) // <-- Value of type 'activeEquationString.Content' (aka '_ViewModifier_Content<activeEquationString>') has no member 'underline' .foregroundColor(currentInd == termInd ? Color.black : Color.gray) } }
7
0
3.7k
May ’20
Untraceable SIGABRT: precondition failure: attribute failed to set an initial value:
Edit: Small changes to posted code to allow easier testing in tmp project. Create a new Single View App that using SwiftUI. C&P View A into ContentView.swift, and View B into a new files called "Dots"I have also found that the issue does not occur when passing 0 to Dots, and have added that to the picker to aid testing.I have spent countless hours doing my best to solve this. Read through too many other posts about this issue being caused by a lot of different things, hacked and slashed code and simple print statement/lldb to try track it down and I'm getting now - I'm pretty frantic right now.This is the same core problem as a previous postView works fine until used in NavigationView/LinkWhilst the workaround stopped the crashes, it was definitely a workaround and not fixing the source. As a consequence, a different "bug" appeared why a custom view partially ignored safe boundaries*. Rather than trying to find a hacky workaround for the workaround, it would be far better to try solve the core issue, but am deeply struggling.As explained in the previous post, View A and B work fine on their own, but when navigation from A to B, that when it fails. Stepping through the code didn't yield much but it be a case of not knowing what to look for.* this view consisted of x views that behaved like horizontal cards, swiping left/right to jump between them. This was achieved by having a HStack(spacing: 0) with a frame x times the width of the screen and a custom Gesture. If you envisage the views as an array, index 0 would be shown by default, and one can swipe amongst them. The first 2 items would correctly respect the inherited height, but 3 onwards would go behind the navigation space and status bar.Note I've attempted to clear the code of some unnecessary content so as to avoid wasting your time.View A (Note I've attempted to clear the code of some unnecessary content so as to avoid wasting your time.)import SwiftUI let lowerBound = 0 let upperBound = 101 struct CapsuleButton: ViewModifier { func body(content: Content) -> some View { content .frame(width: 250, height: 100) .background(Capsule().fill(Color.blue)) .foregroundColor(.black) .font(.system(size: 28, weight: .light)) .padding() } } struct ContentView: View { @State private var pickerIndex: Int = UserDefaults.standard.integer(forKey: "highestDotCovered") - lowerBound @State private var nav: Int? = 0 var body: some View { VStack(spacing: 30) { HStack { Picker(selection: $pickerIndex, label: Text("")) { ForEach(lowerBound..<upperBound) { Text(String($0)) } } } Spacer() NavigationLink(destination: Dots(lowerBound + pickerIndex), tag: 1, selection: $nav) { EmptyView() } Text("Continue") .modifier(CapsuleButton()) // custom look .onTapGesture { // Update storage let currentHighest = UserDefaults.standard.integer(forKey: "highestDotCovered") let highest = max(lowerBound + self.pickerIndex, currentHighest) UserDefaults.standard.set(highest, forKey: "highestDotCovered") // Go to destination self.nav = 1 } } .navigationBarTitle("Quantity Selection") } } struct ContentView_Previews: PreviewProvider { static var previews: some View { NavigationView { ContentView() }.navigationViewStyle(StackNavigationViewStyle()) } }View Bimport SwiftUI private let diam: CGFloat = 60 // ~1/3", 1pt = 1/163" private let maxPhoneDots = 12 struct Dots: View { @State private var dotAlert = false let quantity: Int let dot: some View = Circle() .size(width: diam, height: diam) .fill(Color.red) @State var offsets: [CGSize] = [] init(_ quantity: Int) { let model = UIDevice().model self.quantity = model == "iPad" ? quantity : min(quantity, maxPhoneDots) print(self.quantity) } var body: some View { // NavigationView { // need to wrap geom reader in nav view to avoid crash // VStack { GeometryReader { geom in ForEach(self.genOffsets(maxWidth: geom.size.width, maxHeight: geom.size.height), id: \.self) {offset in self.dot .offset(offset) } .background(Color.clear .contentShape(Rectangle())) // workaround for allowing gestures on clear background } .border(Color.black) // Spacer() // Text("Dots: \(self.quantity)") // } // .navigationBarTitle("") // .navigationBarHidden(true) // }.navigationViewStyle(StackNavigationViewStyle()) } } extension Dots { func genOffsets(maxWidth: CGFloat, maxHeight: CGFloat) -> [CGSize] { var cols = UIDevice().model == "iPad" ? 8 : 4 var rows = UIDevice().model == "iPad" ? 13 : 5 if UIDevice().orientation.isLandscape { (cols, rows) = (rows, cols) //swap cols and rows } var offsets: [CGSize] = [] let availableWidth = max(maxWidth - (CGFloat(cols) * diam), 0) let colSeparation: CGFloat = availableWidth / CGFloat((cols+1)) let availableHeight = max(maxHeight - (CGFloat(rows) * diam), 0) let rowSeparation: CGFloat = availableHeight / CGFloat((rows+1)) let xJitter = colSeparation * 0.49 let yJitter = rowSeparation * 0.49 // grid[row][col] var grid = Array(repeating: Array(repeating: false, count: cols), count: rows) // Generate dot offsets for _ in 0..<quantity { var r, c: Int // Find a random empty cell repeat { r = Int.random(in: 0..<rows) c = Int.random(in: 0..<cols) } while grid[r][c] grid[r][c] = true // Calculate dot's offset // Initial padding from TL corner var x = colSeparation var y = rowSeparation // Separate dot into standard grid slot x += CGFloat(c)*(diam+colSeparation) y += CGFloat(r)*(diam+rowSeparation) // Apply jitter if xJitter != 0 { x += CGFloat.random(in: -xJitter ..< xJitter) } if yJitter != 0 { y += CGFloat.random(in: -yJitter ..< yJitter) } offsets.append(CGSize(width: x, height: y)) } return offsets } } extension CGSize: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(width) hasher.combine(height) } } struct Dots_Previews: PreviewProvider { static var previews: some View { Dots(1) } }
12
0
3.6k
May ’20