Passing arguments over to View is not always available

Hi,


I have a problem with passing arguments over to a View when calling it. I have this View


struct 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 etc


struct 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

Replies

Difference is that

@EnvironmentObject var settingStore: SettingStore

is not private.

Ok, I have changed it to


struct OrderHeaderFilterView: View {
  @Environment(\.presentationMode) var presentationMode

  @EnvironmentObject private var itemFilter: WarehouseOrderFilter
  @EnvironmentObject private var settingStore: SettingStore

  @State var orderTypeArray: [String] = []
  @State var carrierArray: [String] = []

...


but the result is still the same. When I try something like


OrderHeaderFilterView(orderTypeArray: [])


I get


"Argument passed to call that takes no arguments" as error.


What difference does it make whether that environment object is private or not to the arguments?

As far as I tried with your code (with or without `private`),

this

    OrderHeaderFilterView(orderTypeArray: [])

compiles without error.


Something in the hidden parts of your code may be affecting.

Please show full code to reproduce the same issue.

Hi,


Below the two files


//
//  GoodsItemFilter.swift
//  WMS Toolbox
//
//  Created by Max on 2020-02-05.
//  Copyright © 2020 Max. All rights reserved.
//

import SwiftUI

struct GoodsItemFilterView: View {
  @Environment(\.presentationMode) var presentationMode

  @State var ref1Array: [String] = []
  @State var ref2Array: [String] = []
  @State var ref3Array: [String] = []

  @State var stockStatusArray: [String] = []
  @State var zoneArray: [String] = []

  @State var selectorRef1 = 0
  @State var selectorRef2 = 0
  @State var selectorRef3 = 0
  @State var selectorStockStatus = 0
  @State var selectorZone = 0

  var body: some View {
  NavigationView {
  Form{
  Section(header: Text("Zone"), content: {
  Picker(selection: $selectorZone, label:
  Text("Zone")) {
  ForEach(0 ..< zoneArray.count, id:\.self) {
  Text(self.zoneArray[$0])
  }
  }
  })

  Section(header: Text("References"), content: {
  Picker(selection: $selectorRef1, label:
  Text("Reference 1")) {
  ForEach(0 ..< ref1Array.count, id:\.self) {
  Text(self.ref1Array[$0])
  }
  }

  Picker(selection: $selectorRef2, label:
  Text("Reference 2")) {
  ForEach(0 ..< ref2Array.count, id:\.self) {
  Text(self.ref2Array[$0])
  }
  }

  Picker(selection: $selectorRef3, label:
  Text("Reference 3")) {
  ForEach(0 ..< ref3Array.count, id:\.self) {
  Text(self.ref3Array[$0])
  }
  }
  })

  Section(header: Text("Status"), content: {
  Picker(selection: $selectorStockStatus, label:
  Text("Condition")) {
  ForEach(0 ..< stockStatusArray.count, id:\.self) {
  Text(self.stockStatusArray[$0])
  }
  }
  })

  Button(action: {
  self.selectorZone = 0
  self.selectorRef1 = 0
  self.selectorRef2 = 0
  self.selectorRef3 = 0
  self.selectorStockStatus = 0
  }, label: {
  HStack(){
  Spacer()
  Image(systemName: "return")
  Text("Reset filters")
  Spacer()
  }

  })

  }.navigationBarTitle("Filter")
  .navigationBarItems(leading: (
  Button(action: {
  self.presentationMode.wrappedValue.dismiss()
  }, label: {
  Text("Cancel")
  }
  )
  ), trailing: (
  Button(action: {

  self.presentationMode.wrappedValue.dismiss()
  }, label: {
  Text("Done")
  }
  )
  ))
  }.onAppear{
  self.ref1Array.insert("***ALL***", at: 0)
  self.ref2Array.insert("***ALL***", at: 0)
  self.ref3Array.insert("***ALL***", at: 0)

  self.stockStatusArray.insert("***ALL***", at: 0)
  self.zoneArray.insert("***ALL***", at: 0)


  }
  }
}

struct GoodsItemFilter_Previews: PreviewProvider {
  static var previews: some View {
  GoodsItemFilterView(ref1Array: ["MAX100", "MAX101", "MAX102"], ref2Array: ["REF2_100", "REF2_101"], ref3Array: ["REF3_100", "REF3_101"])
  }
}



//
//  OrderHeaderFilter.swift
//  WMS Toolbox
//
//  Created by Max on 2020-01-24.
//  Copyright © 2020 Max. All rights reserved.
//

import SwiftUI
//import Combine

struct OrderHeaderFilterView: View {
  @Environment(\.presentationMode) var presentationMode

  @State var orderTypeArray: [String] = []
  @State var carrierArray: [String] = []

  @State var fromStatus2 = UserDefaults.standard.string(forKey: "view.orderHeaderFilter.fromStatus")
  // @State private var fromStatus2 = "040"

  @State private var direction = ""
  @State private var fromStatus = ""
  @State private var toStatus = ""
  @State private var orderType = ""


  @State var selectorOrderType = 0
  @State var selectorCarrier = 0

  @State private var selectorIndex = 1
  @State private var fromStatusSelectorIndex = 6
  @State private var toStatusSelectorIndex = 2

  @State private var directions = ["Inbound","Outbound","Both"]

  private var orderStatusFromArray: [String] = ["005", "010", "022", "025", "030", "035", "040", "045", "046", "047", "060"]
  private var orderStatusToArray: [String] = ["005", "010", "022", "025", "030", "035", "040", "045", "046", "047", "060"]

  @State var orderStatus = OrderStatus.s05

  enum OrderStatus: String, CaseIterable, Identifiable {
  case s05 = "005"
  case s10 = "010"
  case s22 = "022"
  case s25 = "025"
  case s30 = "030"
  case s35 = "035"
  case s40 = "040"
  case s45 = "045"
  case s46 = "046"
  case s60 = "060"

  var id: String { rawValue }
  }




  enum Direction: String, CaseIterable{
  case outbound = "1"
  case inbound = "2"
  case both = "3"

  init(type: String) {
  switch type {
  case "1": self = .outbound
  case "2": self = .inbound
  case "3": self = .both
  default: self = .both
  }
  }

  var text: String {
  switch self {
  case .outbound: return "Outbound"
  case .inbound: return "Inbound"
  case .both: return "Both"
  }
  }
  }

  init(){
  //nothing here
  }

  var body: some View {

  return NavigationView{
  Form{
  HStack{
  Text("Direction")
  Spacer()
  Picker(selection: $direction, label:
  Text("Direction")) {
  ForEach(directions, id:\.self) {
  status in
  Text(status)
  }
  }
  .pickerStyle(SegmentedPickerStyle())
  }

  Picker(selection: $fromStatus, label:
  Text("From Status")) {
  ForEach(orderStatusFromArray, id:\.self) {
  status in
  Text(status)
  }
  }

  Picker(selection: $toStatus, label:
  Text("To Status")) {
  ForEach(orderStatusFromArray, id:\.self) {
  status in
  Text(status)
  }
  }

  }.navigationBarTitle("Filter")
  .navigationBarItems(leading: (
  Button(action: {
  self.presentationMode.wrappedValue.dismiss()
  }, label: {
  Text("Cancel")
  }
  )
  ), trailing: (
  Button(action: {


  self.presentationMode.wrappedValue.dismiss()
  }, label: {
  Text("Done")
  }
  )
  ))

  }.onAppear{

  self.direction = UserDefaults.standard.string(forKey: "view.orderHeaderFilter.direction")!
  self.fromStatus = UserDefaults.standard.string(forKey: "view.orderHeaderFilter.fromStatus")!
  self.toStatus = UserDefaults.standard.string(forKey: "view.orderHeaderFilter.toStatus")!

  self.orderTypeArray.insert("***ALL***", at: 0)
  self.carrierArray.insert("***ALL***", at: 0)



  }
  }
}

struct OrderHeaderFilter_Previews: PreviewProvider {
  static var previews: some View {
  OrderHeaderFilterView()
  }
}

Nobody an idea or having the same issue?

`ref1Array` has default argument `= []`. That's why you don't need to supply argument.

Also, initializing `@State` only works the first, the next time you access the view, it'll retain the old state, even if you supply different argument.

If that's not what you want, use normal `let` instead.

Hi Lantua,


Thanks but if you look at my example above you can see that GoodsItemFilterView also has the arrays initialized and there I can still pass the arguments so why can't I do that for the OrderHeaderFilterView?


Max

Found the issue(s):

I had this piece in the code

init(){ //nothing here }

This needs to be removed, otherwise it will not ask for any variables.

The other issue is the one I don't understand:

private var orderStatusFromArray: [String] = ["005", "010", "022", "025", "030", "035", "040", "045", "046", "047", "060"]
private var orderStatusToArray: [String] = ["005", "010", "022", "025", "030", "035", "040", "045", "046", "047", "060"]

If I change the var to let, it works as expected. Another option is to remove the private at the beginning. So it looks like as soon as you have a

private var ...

in your code, all arguments become private. Maybe I am missing something here but that seems like a bug to me.

Right, if you have implemented initializers, Swift will not generate member-wise one for you (which also answers your previous response, so I'm not gonna reply to that).
Also, the arguments in the memberwise follow initializer follows the variable's access control. If you have private variable, you can only specify it with private initializer, not from different file.


Could you also elaborate the "work as expected" version? If you change var to let, you can't supply it as an argument, which iirc, is not what you want.

PS


I'd suggest that you try to make the code as small as possible when asking. It's not easy looking through 300+ lines of code just to reply to a forum, especially when a large part of them is irrelevant. Like this one, the only important thing is that you don't have the initializer you want. You may want to create new playground to experiment the rule surrounding initializer using a mock class (like Foo). You may even figure it out on your own by doing that. And if your question pertains only the swift language, not particular framework, you may want to try http://forums.swift.org