Post

Replies

Boosts

Views

Activity

Reply to View Initializes Twice
Any way to reduce the amount of times the view is initialized or api calls being made would be greatly appreciated! In SwiftUI, initializers of Views may be called unpredictable times. You should better not make API calls in the initializers of Views. Better try onAppear.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Feb ’21
Reply to I get the error "Unexpectedly found nil while implicitly unwrapping an Optional value" when calling a protocol method
how do I make the value in onlineViewers stay when the user leaves the app and comes back?  That's a little bit too far from your original question of this thread. For a small amount of app state info like labelTitle, UserDefaults would be a good place. Also you should better learn about App State Restoration features of iOS: Preserving Your App's UI Across Launches - https://developer.apple.com/documentation/uikit/view_controllers/preserving_your_app_s_ui_across_launches. (There may be some other documents. Non-Apple articles might be more easy to read, as usual.) If you cannot make it work with your code, you should better start a new thread focused on it.
Topic: Programming Languages SubTopic: Swift Tags:
Feb ’21
Reply to I get the error "Unexpectedly found nil while implicitly unwrapping an Optional value" when calling a protocol method
Thanks for your updated code. Your code is still missing storeButtonIsSelected, but many important things got clarified and I filled the missing part by guess. So, your view hierarchy (transition structure) is something like this, OK? ViewContoller |-(startLivePressed)----Segue(id: segueToCamera)- LiveViewController | ↑ | No direct segue connection | ↓-(storeButtonPressed)--Segue(id: segueToStore)-- StoreViewController (I have renamed all the type names with Capitalized identifiers if not yet. If you have some specific reason that you cannot follow this very common Swift coding rule, please re-interpret the type names.) In this transition structure, you cannot use delegate pattern. With using segue, the target view controllers will be instantiated at each transition, so once a view controller is dismissed, it is sort of not alive. But the delegate needs to be alive while the view controller using it is alive. In other words, while StoreViewController is presented, there is no alive LiveViewController. If you want to keep this transition structure, you may need to give up using delegate pattern. Or else, you need to re-design the view hierarchy completely. When keeping your transition structure, shared object would be a better strategy. MyModel.swift: import Foundation class MyModel { static let shared = MyModel() var labelTitle: String = "" } StoreViewController class StoreViewController: UIViewController { // var labelDelegate: LabelMaker! @IBAction func viewersTapped(_ sender: UIButton) { MyModel.shared.labelTitle = sender.currentTitle ?? "" // labelDelegate.labelMaker(value: sender.currentTitle!) } //... } LiveViewController class LiveViewController: UIViewController { // let storeView = StoreViewController() @IBOutlet weak var stopButton: UIButton! @IBOutlet var onlineViewers: UILabel! override func viewDidLoad() { super.viewDidLoad() // storeView.labelDelegate = self } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) onlineViewers.text = MyModel.shared.labelTitle } } If you do not prefer this, you can utilize delegate pattern with making ViewController as a delegate, but it may need a little more complex code. (Please remember ViewController is still alive while StoreViewController is presented.) By the way, some of your protocols SegueDestination, SourceForB and SourceForC are making your code more complex than it should be. That is making it very hard to read your code.
Topic: Programming Languages SubTopic: Swift Tags:
Feb ’21
Reply to Broken NavigationLink behavior when using @StateObject and a ForEach inside a Form
Can anything advise if there is a logical issue with the code or is it a SwiftUI bug? Very likely a big flaw in the current implementation of SwiftUI. Better send a feedback to Apple. Any suggestions for a workaround? Moving the NavigationLink out of Form looks like working in a simple case. struct MainView: View { @StateObject var viewModel = ViewModel() var body: some View { NavigationView { ZStack { NavigationLink ( destination: ChildView(isActive: $viewModel.isActive), isActive: $viewModel.isActive, label: { EmptyView() } ) Form { HStack { Text("Go to child view") Spacer() Image(systemName: "chevron.forward") } .contentShape(Rectangle()) .onTapGesture { print(viewModel.isActive) viewModel.isActive = true } ForEach(1..4) { Text("\($0)") } } } .navigationBarTitle("Test") } } } There may be other better workarounds, but I could not find any till now.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Feb ’21
Reply to .debounce() not working as expected
I am trying to debounce the API call when a user enters something in TextField. Not clear enough, but I guess you should better make the TextField change as a publisher and apply debounce on it. As described in the documentation - https://developer.apple.com/documentation/combine/fail/debounce(for:scheduler:options:%29 This operator is useful to process bursty or high-volume event streams where you need to reduce the number of values delivered to the downstream to a rate you specify. dataTaskPublisher emits only one event, not bursty nor high-volume event streams.
Topic: Programming Languages SubTopic: Swift Tags:
Feb ’21
Reply to Find which button is pressed in a Grid in SwiftUI
But it's giving me the following error. In Swift, nested type does not work as a constraining something, but is just a namespace. If you want to put some constraint for the generic argument, you may need to introduce another protocol: protocol MenuItem {} extension Menu.UserType: MenuItem {} extension Menu.Main: MenuItem {} struct MenuButtonItemType: MenuItem: View { //... }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Feb ’21
Reply to Updating item in nested observed array with swiftUI
Is there a simpler way to eliminate the keeping track of all the indices. As far as I know, there are no ways provided in the current SwiftUI framework. You would be able to create some wrapper to make things look simpler, for example: struct ForEachMutableData, Content: View: DynamicViewContent where Data : RandomAccessCollection & MutableCollection, Data.Index: Hashable { var data: Data { dataBinding.wrappedValue } var dataBinding: BindingData var content: (BindingData.Element)-Content init(_ dataBinding: BindingData, content: @escaping (BindingData.Element)-Content) { self.dataBinding = dataBinding self.content = content } var body: some View { ForEach(data.indices, id: \.self) {index in content(dataBinding[index]) } } } And use it as: var body: some View { VStack (alignment: .leading) { List { ForEachMutable($eventsVM.events) { eventBinding in VStack { Text(eventBinding.wrappedValue.title) .font(.title) Text("items todo: \(eventBinding.wrappedValue.totalTodos)") .font(.title3) ForEachMutable(eventBinding.todos) { todoBinding in HStack { Image(systemName: todoBinding.wrappedValue.done ? "checkmark.square" : "square") .resizable() .frame(width: 24, height: 24) .foregroundColor(todoBinding.wrappedValue.done ? .blue : .gray) .font(.system(size: 20, weight: .regular, design: .default)) Text(todoBinding.wrappedValue.title) Spacer() }.padding(5.0) .onTapGesture(perform: { todoBinding.wrappedValue.done.toggle() }) } } } } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Feb ’21
Reply to Changing a value with the stepper
struct FeedProduct { Thanks. If you created a new project and copied the code in your opening post, you would have found what were missing more easily. I can't use = Int(sender.value) because this resets to 0 each time I press the button, I guess you cannot use = Int(sender.value) because you are not setting the value property of the stepper. how can I update the values without using removeButtons() and addButtons()? You just need to update the text property of the corresponding UILabel in the action method stepperValueChanged. To achieve this, you need to access the right UILabel in that method. To make things easier, you can encapsulate each row into a class: LabelStepper.swift import UIKit class LabelStepper: UIStackView { typealias ActionHandler = (LabelStepper)-Void /// A handler called on `.valueChanged` of `stepper` var onValueChanged: ActionHandler? let label: UILabel let rationAmount: UILabel //- The right UILabel let stepper: UIStepper init(text: String, value: Int, onValueChanged: ActionHandler?) { let label = UILabel(frame: .zero) let rationAmount = UILabel(frame: .zero) let stepper = UIStepper(frame: .zero) self.label = label self.rationAmount = rationAmount self.stepper = stepper self.onValueChanged = onValueChanged super.init(frame: .zero) let horizontalStack = self horizontalStack.axis = .horizontal horizontalStack.alignment = .firstBaseline //- You can try other values... //horizontalStack.distribution = .fillEqually label.text = text horizontalStack.addArrangedSubview(label) rationAmount.text = "\(value)" horizontalStack.addArrangedSubview(rationAmount) stepper.value = Double(value) //- Please do not forget to set `value` stepper.minimumValue = 0 stepper.maximumValue = 900 stepper.wraps = false stepper.autorepeat = false stepper.addTarget(self, action: #selector(stepperValueChanged(_:)), for: .valueChanged) horizontalStack.addArrangedSubview(stepper) } required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc func stepperValueChanged(_ sender: UIStepper) { rationAmount.text = "\(Int(sender.value))" //- Update the `text` property of the right UILabel onValueChanged?(self) } } And use it in the VC: func addButtons() { for (feed,amount) in feedInventory where amount 0 { let filteredProducts = feedProducts.filter { $0.code.contains(feed)} for feedProduct in filteredProducts { let rationIndex = rationArrayPosition[feedProduct.code]! let value = myHorses[horseIndex].ration[rationIndex] let horizontalStack = LabelStepper( text: "\(feedProduct.name)", value: value ) {labelStepper in myHorses[horseIndex].ration[rationIndex] = Int(labelStepper.stepper.value) } horizontalStack.stepper.accessibilityLabel = "\(feedProduct.code)" feedStack.addArrangedSubview(horizontalStack) } } }
Topic: Programming Languages SubTopic: Swift Tags:
Feb ’21
Reply to variable in func not working
a error that says Cannot find 'textfield' in scope here is the is the code. Isn't it Cannot find 'test' in scope? In your current code (please use Code block), testfunc() is places outside of ContentView, so its property test is not visible there: struct ContentView: View { @State var test = "this is a test" var body: some View { Text("Hello") } //- End of `body` } //- End of `ContentView` func testfunc() { test = "test" } If you want to write a function which modifies some instance property, it needs to be placed inside the same type: struct ContentView: View { @State var test = "this is a test" var body: some View { Text("Hello") } //- End of `body` func testfunc() { test = "test" } //- End of `testfunc()` } //- End of `ContentView`
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Feb ’21
Reply to Error when taking out unused variable
In the latest code for AddView , colorScheme is used. As far as I tried (keep using colorScheme and removing the line @Environment(\.colorScheme) var colorScheme), I can reproduce the same error. Check if the variable is really unused, before removing the declaration.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Feb ’21