Hi,I just started playing around with SwiftUI and have stumbled over something: in my "regular" apps, my view controllers take care of loading data from a web service (triggered by a function called in the ViewDidLoad() part) and then hand the information over to the views.If I understand the concept of SwiftUI correctly, this whole piece of loading data is no longer managed in the View files but somewhere outside.So in my app now I have a class of WarehouseOrder and created another class called WarehouseOrderController that is responsible for loading the data from the server and storing it in an array (happens in function loadData() called by the init() of that class)@Published var warehouseOrders:[WarehouseOrder] = []From my main menu I call the View WarehouseOrderOverview via a NavigationLinkstruct WarehouseOrderOverview: View {
@EnvironmentObject var settingStore: SettingStore
var warehouseOrderController = WarehouseOrderController()
var body: some View {
List(warehouseOrderController.warehouseOrders){ warehouseOrder in
Text(warehouseOrder.orderRef)
}
}
}What I don't get is that when I start the app, it is triggering the init() of WarehouseOrderController already when I am in the main menu. How can I change it that the data only gets loaded when I actally trigger the NavigationLink to WarehouseOrderOverview?Max
Post
Replies
Boosts
Views
Activity
for Hi,I am retrieving data from a web service in an URLSession and store all the entries to an arrayself.warehouseOrders.append(warehouseOrder)The array is used in another view as data source for a List() item but now I get this error message:Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.My question is: where is SwiftUI expecting me to put the operator receive(on:)) to fix this?I have kinda solved it by changing the code toDispatchQueue.main.async {
self.warehouseOrders.append(warehouseOrder)
}but I am not sure if that is the correct approach here?See https://forums.developer.apple.com/thread/128068for more details on my code - I have actually posted this already there as a reply but for some reason it still gets moderated for almost 24 hours ...Max
Hi,I have this code to change my background color based on the enum AddressTypeenum AddressType: String, CaseIterable{
case shipFrom = "1"
case shipTo = "2"
case unknown = "999"
init(type: String) {
switch type {
case "1": self = .shipFrom
case "2": self = .shipTo
default: self = .unknown
}
}
var text: String {
switch self {
case .shipFrom: return "Ship From"
case .shipTo: return "Ship To"
case .unknown: return "N/A"
}
}
}.background(addressType.self == AddressType.shipFrom ? Color.green : Color.yellow)Question is now: what do I have to do if I want my shipFrom in Color.green and my shipTo in Color.orange? I have tried adding a 2nd .background() for the shipTo but that did not work.Is there any way to work with more than 1 IF clause?Max
Hi,I have this pickerPicker("From status", selection: $fromStatusSelectorIndex) {
ForEach(0 ..< orderStatusFromArray.count) { index in
Text(self.orderStatusFromArray[index]).tag(index)
}
}that is using data from this array:private var orderStatusFromArray: [String] = ["005", "010", "022", "025", "030", "035", "040", "045", "046", "047", "060"]When saving my values, I store the picker selection in UserDefaultsself.settingStore.defaults.set(self.orderStatusFromArray[self.fromStatusSelectorIndex], forKey: "view.orderHeaderFilter.fromStatus")What I don't understand: where in my code do I have to place it to set the picker to the saved default value? Let's say user saved the settings with status 025 (orderStatusFromArray[3]) - where do I explain to SwiftUI that the picker should be set to 3 when the view is loaded?Max
I have this code in my SwiftUI view structHStack{
Text("Direction")
Spacer()
Picker("Direction", selection: $selectorIndex) {
ForEach(0 ..< directions.count) { index in
Text(self.directions[index]).tag(index)
}
}
.pickerStyle(SegmentedPickerStyle())
}
Picker("From status", selection: $fromStatus2) {
ForEach(Self.orderStatusFromArray, id: \.self) { status in
Text(status)
}
}So far so good. If I now break it on purpose by changing line 12 toPicker("From status", selection: "025") {Xcode now indicates that there is an error on line 06Generic parameter 'S' could not be inferred
1. In call to initializer (SwiftUI.Text)Shouldn't it rather indicate that the error is on line 12 instead of 6?Max
Hi,From my ContentView I use a NavigationLink to go to an Order Overview WarehouseOrderOverview()NavigationView{
ScrollView{
VStack{
NavigationLink(destination: WarehouseOrderOverview().environmentObject(self.settingStore).navigationBarTitle("Orders")) {
MenuButtonNavigation(title: "Order overview", color: Color.gray, icon: "doc.text.magnifyingglass").padding(.top)
}WarehouseOrderOverview:var body: some View {
List(warehouseOrderController.warehouseOrders){ warehouseOrder in
NavigationLink(destination: WarehouseOrderView(warehouseOrder: warehouseOrder).environmentObject(self.settingStore).navigationBarTitle("Details")){
OrderTableRow(warehouseOrder: warehouseOrder)
}So far so good. If I now tap a row in that view, I get to the order details view WarehouseOrderViewNavigationView{
ScrollView() {
VStack{
VStack(spacing: -25) {
HStack(spacing: -25) {
NavigationLink(destination: WarehouseOrderLinesView(warehouseOrderLines: warehouseOrderLineController.warehouseOrderLines)){
TaskSummaryView(title: "Total Lines", color: .blue, icon: "list.dash", value: warehouseOrderLineController.warehouseOrderLines.count)
}Problem is now that when I tap the TaskSummaryView, it opens the WarehouseOrderLinesView with two navigation bars on top (one going back to Orders, the other one to the Order details [too bad I cannot post a screenshot here ...])I believe the issue is that I create a new NavigationView in my WarehouseOrderView but I get an error when trying to use the NavigationLink without embedding it in a NavigationView. Or is there a better way than NavigationLink to open the view WarehouseOrderLinesView?Max
Hi,Is there a way to navigate to another view after tapping a row WITHOUT using NavigationLink (see here why the NavigationLink gives me a headache: https://forums.developer.apple.com/thread/128454)I have tried@State private var presentDetails: Bool = falseandList(warehouseOrderController.warehouseOrders){ warehouseOrder in
OrderTableRow(warehouseOrder: warehouseOrder).onTapGesture {
print(warehouseOrder.orderRef!)
self.presentDetails = true
}.sheet(isPresented: self.$presentDetails){
WarehouseOrderView(warehouseOrder: warehouseOrder).environmentObject(self.settingStore)
}
}but that always brings the new view up as a modal while I actually want it to look like as if I had used the NavigationLink (meaning: not floating over the other view).Any ideas?Max
Hi,I am fetching data for my table view via a web service. Based on the request the result set can vary between 1 row and 20,000 rows. I know that usually my users are just interested in the first 1,000 rows of the data so I am wondering to have an approach where the initial web service call just loads the top 1,000 rows and when the user scrollls down the list and gets to the 800s, 900s or end of table, another request is triggered to fetch the next 1,000 rows - kinda similar to a Twitter feed where the data gets loaded once you scrolld down.What would the events be to trigger the call for the next set of data or is there another way to make this happen?Max
Hi,With reference to https://forums.developer.apple.com/thread/129860 I am looking for a way to trigger an event when the user scrolls down to the end of a List.Recommended solution from the thread above mentionsfunc tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCellas a solution and then to look at the index of the current cell.My List looks like thisList(warehouseOrderController.warehouseOrders){ warehouseOrder in
NavigationLink(destination: WarehouseOrderView(warehouseOrder: warehouseOrder)
.environmentObject(self.settingStore)
){
OrderTableRow(warehouseOrder: warehouseOrder)
}
}So the question is: how do I get the index of the current row displayed and how do I trigger a function when the user reaches row 900/1000?
Hi,My app is being distributed over the Apple Business Manager program and I have noticed that every time I submit an updated version of the app, I have to increment the version number. My other app (regular distribution) only requires an update to the Build version and the version itself could remain identical.Is that supposed to be like that?Max
Hi,I have a Localizable.strings file for English and German. In there I have these entries"orderOverview" = "Order Overview";
"goal" = "XXXXXXXXXXXrder Overview";in my ContentView I haveNavigationLink(destination: WarehouseOrderOverview().environmentObject(self.settingStore).navigationBarTitle("orderOverview")) {
MenuButtonNavigation(title: "goal", color: Color.gray, icon: "doc.text.magnifyingglass").padding(.top)
}When I now run the app, it actually shows "goal" and "orderOverview" instead of the translated values. Is there anything else I have to do?Max
Hi,I have a view that is triggred by a button touch. It appears nicely, all good. Now I want the View to disappear automatically again after a few seconds. How do I do that?!Below my test project//
// ContentView.swift
// FadeOut
//
// Created by Max on 2020-03-19.
// Copyright © 2020 Max. All rights reserved.
//
import SwiftUI
struct ContentView: View {
@State private var presentClipboardView = false
@State private var scale: CGFloat = 1.0
var body: some View {
VStack{
Button(action: {
let pasteboard = UIPasteboard()
pasteboard.string = "http://I_AM_A_URL.com"
withAnimation(.easeInOut(duration: 2)) {
self.presentClipboardView.toggle()
}
}, label: {
HStack {
Image(systemName: "list.dash")
.padding(.trailing)
VStack(alignment: .leading) {
Text("Open URL")
.font(.headline)
}
Spacer()
}
}
)
if(self.presentClipboardView){
LabelView()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct LabelView: View {
var body: some View {
Text("URL copied to clipboard!")
.padding(10)
.font(.title)
.foregroundColor(.white)
.background(RoundedRectangle(cornerRadius: 8).fill(Color.green).shadow(color: .gray, radius: 3))
}
}
Hi,I have a problem with passing arguments over to a View when calling it. I have this Viewstruct GoodsItemFilterView: View {
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject private var goodsItemFilter: GoodsItemFilter
@State var ref1Array: [String] = []
@State var ref2Array: [String] = []
@State var ref3Array: [String] = []
...and when I call it I can pass over the values of the arrays as arguments:GoodsItemFilterView(ref1Array: ["MAX100", "MAX101", "MAX102"], ref2Array: ["REF2_100", "REF2_101"], ref3Array: ["REF3_100", "REF3_101"])Now I have another view which is basically a copy of this one with a few changed names etcstruct OrderHeaderFilterView: View {
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var settingStore: SettingStore
@EnvironmentObject private var itemFilter: WarehouseOrderFilter
@State var orderTypeArray: [String] = []
@State var carrierArray: [String] = []
...and when I call it, it is not prompting me to pass over the arrays as arguments:OrderHeaderFilterView()What is the difference between those 2 views that the one is asking for arguments on initilization and the other one isn't? To be clear, in the end I want to pass over the arguments, so GoodsItemFilterView() is doing exactly what I need.Max
Hi,I have a view that has navigation bar items and I embed that view in a TabView. But when doing that, the bar items no longer appear. If I call the view outside of a TabView everything works as expected.Below a small sample project to illustrate my issue://
// ContentView.swift
// TabView
//
// Created by Max on 2020-03-30.
// Copyright © 2020 Max. All rights reserved.
//
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView{
NavigationLink(destination: WarehouseOrderTabView()){
Text("Click me")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct WarehouseOrderTabView: View {
var body: some View {
TabView{
TabView1().navigationBarTitle("Dashboard")
.tabItem {
Image(systemName: "gauge")
Text("Dashboard")
}
TabView2().navigationBarTitle("Orders")
.tabItem {
Image(systemName: "list.dash")
Text("Orders")
}
}
}
}
struct TabView1: View {
var body: some View {
Text("TabView 1")
//I would expect to see those bar items when displaying tab 1
.navigationBarItems(trailing: (
HStack{
Button(action: {
}, label: {
Image(systemName: "arrow.clockwise")
.font(.title)
})
.padding(.init(top: 0, leading: 0, bottom: 0, trailing: 20))
Button(action: {
}, label: {
Image(systemName: "slider.horizontal.3")
.font(.title)
})
}
))
}
}
struct TabView2: View {
var body: some View {
Text("TabView 2")
}
}What am I missing here?Max
Hi,I have a picker of style SegmentedPickerStyle and based on the selection (Inbound, Outbound) a chart below displays different data. How can I send an event to my chart model to reload the data based on the picker selection? I know how to send the picker value to the model but how do I trigger it every time when the picker changes?I have tried something likeSunburstView(configuration: self.sunburstController.configuration).onAppear{
self.sunburstController.loadNodes(countMode: self.selectedCountMode, direction: self.selectedDirection)
}but that obviously only works first time the view is loading and not after every picker change.Thanks for any hints!Max