Variable used before being initialized with an EnvironmentObject in SwiftUI - variables

I'am using an init to initialize my variable groupManager from the environmentObject objCOurse.
But Xcode tells me Variable 'self.groupeManager' used before being initialized
Where is the mistake ?
struct DepartsSimultanesView: View {
#EnvironmentObject var objCourse : CourseActuelle
#State var selectedParcoursIndexArray : [Int] = []
#State var groupeManager : GroupeManager
init(groupeManager : GroupeManager) {
self.groupeManager = GroupeManager(courseId: objCourse.id!) // Variable 'self.groupeManager' used before being initialized
for _ in (0 ..< groupeManager.groupeList.count) {
self.selectedParcoursIndexArray.append(0)
}
}

Thanks to #vadian comments, here what is working for me :
init(groupeManager : GroupeManager, objCourse : CourseActuelle) {
_groupeManager = State(initialValue: GroupeManager(courseId: objCourse.id!))
var Varray : [Int] = []
for _ in (0 ..< groupeManager.groupeList.count) {
Varray.append(0)
}
_selectedParcoursIndexArray = State(initialValue: Varray)
print(selectedParcoursIndexArray)
}

Related

SwiftUI VIEW change variable from external class

A similar question was asked before, and with the help of several netizens, some codes have been changed.
When press .. "Show Next View" >> "Change-Me" >> "Return" .. why the variable "price" can not change to 9 ....
I am a novice, I know there code have something wrong I can't find it and hope someone can guide me, Thanks!
class ExtenalClass {
let SubFrutis = ContentView()
func ExtChangePrice() {
SubFrutis.fChangePrice()
}
}
struct ContentView: View {
#State var price: Int = 0
#State var vPresent = false
func fChangePrice() {
price = 9
print("Price Value is: \(String(price))")
}
var body: some View {
VStack {
Text(String(price)).padding()
Button("Show Next View") { self.vPresent = true }
.sheet(isPresented: $vPresent) {
SecondView(vPresent: self.$vPresent)
}.padding()
Button("Add-Me") { price += 1 }.padding()
Button("RESET") { price = 1 }.padding()
}
}
}
struct SecondView: View {
#Binding var vPresent: Bool
var vExtenal = ExtenalClass()
var body: some View {
Button("Change-Me") {
vExtenal.ExtChangePrice()
// ContentView().fChangePrice()
}.padding()
Button("Return") { self.vPresent = false }
}
}

Reset State Variables To Initial Values xcode

What is the best way to go about resetting state variables, using a button. I've tried a load of different funcs but none work.
I'm trying to use this button:
primaryButton: .destructive(Text("Delete")) {
Code
},secondaryButton:
.cancel()
To reset these State variables:
#State var statsValue1 = 0
#State var statsValue2 = 0
#State var statsValue3 = 0
#State var statsValue4 = 0
#State var statsValue5 = 0
#State var statsValue6 = 0
(which are in the main content view)
How about using a view model, the #Published property wrapper notifies about any changes of the model and the reset function creates a new instance
struct Model {
var value1 = 0
var value2 = 0
var value3 = 0
}
class ViewModel : ObservableObject {
#Published var model = Model()
func reset() {
model = Model()
}
}
and a simple test logic in the content view
struct ContentView : View {
#StateObject var viewModel = ViewModel()
var body : some View {
VStack(spacing: 20) {
Text("Value 1: \(viewModel.model.value1)")
Text("Value 2: \(viewModel.model.value2)")
Text("Value 3: \(viewModel.model.value3)")
Divider()
Button ( "Delete", role: .destructive, action: viewModel.reset )
Button { viewModel.model.value1 += 1 } label: { Text("Increment value 1") }
Button { viewModel.model.value2 += 1 } label: { Text("Increment value 2") }
Button { viewModel.model.value3 += 1 } label: { Text("Increment value 3") }
}
}
}

How to add elements to a HStack Using ForEach SwiftUi

Im fairly new to Swift and I'm trying to produce a HStack (that will be used in a progress bar) of element and to be able to add elements with a button.
Im not sure if I should use a variable in the ForEach(1..<Variable) section or use another method. Here is the code I have so far but it did not work.
struct ContentView: View {
#State var fill : CGFloat = 0
#State var NumberOfCircles : Int = 0
var body: some View {
HStack(spacing:100) {
ForEach(0..<NumberOfCircles){ _ in
MyShape()
}
Button(action: {NumberOfCircles = 5}, label: {
Text("Button")
})
}
ForEach in SwiftUI needs a constant range to loop over. However,
as the error suggests, if you conform to Identifiable or use ForEach(_:id:content:) and provide an explicit id it is happy. So try this:
struct ContentView: View {
#State var fill: CGFloat = 0
#State var NumberOfCircles: Int = 0
var body: some View {
HStack(spacing: 20) {
ForEach(0..<NumberOfCircles, id: \.self){ _ in // <-- here
MyShape()
}
Button(action: {NumberOfCircles = 5}){
Text("Button")
}
}
}
}
I'm not sure what's your problem, but I tested this code and it works:
struct ContentView: View {
#State var numberOfCircles = 1
var body: some View {
VStack {
HStack {
ForEach(0..<numberOfCircles, id:\.self) { _ in
Circle()
.frame(width: 30, height: 30)
}
}
Button { numberOfCircles = 5 } label: {
Text("Add Circles")
}
}
}
}
Btw, naming convention for variables in Swift is camelCase. That means that declaring a variable you should name it numberOfCircles , not NumberOfCircles . The first uppercase letter is reserved for naming Classes, Structs and Protocols.

Looking for an easy custom View for SwiftUI:picker

Has anyone created a custom View to use a picker? I would like to use many pickers without clogging my view definition.
Here is my easy to use custom view to use SwiftUI picker:
import SwiftUI
struct MyPicker : View {
#State var title:String = ""
#State var display:Bool = false
#State var chosenItem:Int = 0
var choices:[String] = []
var setPickerValue:(Int)->Void
var body: some View {
HStack {
Text("\(title)")
Button(action: {
self.display.toggle()
}) {
Text("\(choices[chosenItem])")
}
if display {
Picker(selection: $chosenItem, label:Text("")) {
ForEach(0 ..< choices.count) {
Text(self.choices[$0])
}
}
.onTapGesture{
self.display.toggle()
self.setPickerValue(self.chosenItem)
}
}
}
}
init(t:String, c:[String], initChoice: Int, funcSetValue:#escaping (Int)->Void) {
_title = State(initialValue: t)
choices = c
_chosenItem = State(initialValue: initChoice)
setPickerValue = funcSetValue
}
}
struct MyView : View {
#State var imageChoice:Int = 0
var imageList:[String] = ["imageOne", "imageTwo", "imageThree"]
var body: some View {
MyPicker(t:"Images", c:imageList, initChoice:0, funcSetValue:setImageChoice)
}
func setImageChoice(v:Int) -> Void {
imageChoice = v
}
}

SwiftUI: Is it possible to automatically move to the next textfield after 1 character is entered?

I trying to make a SwiftUI app where after entering one letter in a TextField the cursor automatically moves to the next TextField. The UI is pretty much like this.
In Swift/IB, it looks like this was done with delegates and adding a target like in this post:
How to move to the next UITextField automatically in Swift
But can't find any documentation for using delegates/targets in SwiftUI.
I tried following this post:
SwiftUI TextField max length
But this has not worked for me. Setting the .prefix(1) does not seem to make a difference. The TextField still accepts any amount of characters and when moved to the next TextField does not reduce the characters entered to only the first character.
In SwiftUI's current state, is it possible to automatically move to the next TextField after 1 character is entered?
Thanks for any help!
It can be done in iOS 15 with FocusState
import SwiftUI
///Sample usage
#available(iOS 15.0, *)
struct PinParentView: View {
#State var pin: Int = 12356
var body: some View {
VStack{
Text(pin.description)
PinView(pin: $pin)
}
}
}
#available(iOS 15.0, *)
struct PinView: View {
#Binding var pin: Int
#State var pinDict: [UniqueCharacter] = []
#FocusState private var focusedField: UniqueCharacter?
var body: some View{
HStack{
ForEach($pinDict, id: \.id, content: { $char in
TextField("pin digit", text:
Binding(get: {
char.char.description
}, set: { newValue in
let newest: Character = newValue.last ?? "0"
//This check is only needed if you only want numbers
if Int(newest.description) != nil{
char.char = newest
}
//Set the new focus
DispatchQueue.main.async {
setFocus()
}
})
).textFieldStyle(.roundedBorder)
.focused($focusedField, equals: char)
})
}.onAppear(perform: {
//Set the initial value of the text fields
//By using unique characters you can keep the order
pinDict = pin.description.uniqueCharacters()
})
}
func setFocus(){
//Default to the first box when focus is not set or the user reaches the last box
if focusedField == nil || focusedField == pinDict.last{
focusedField = pinDict.first
}else{
//find the index of the current character
let idx = pinDict.firstIndex(of: focusedField!)
//Another safety check for the index
if idx == nil || pinDict.last == pinDict[idx!]{
focusedField = pinDict.first
}else{
focusedField = pinDict[idx! + 1]
}
}
//Update the Binding that came from the parent
setPinBinding()
}
///Updates the binding from the parent
func setPinBinding(){
var newPinInt = 0
for n in pinDict{
if n == pinDict.first{
newPinInt = Int(n.char.description) ?? 0
}else{
newPinInt = Int(String(newPinInt) + n.char.description) ?? 0
}
}
pin = newPinInt
}
}
//Convert String to Unique characers
extension String{
func uniqueCharacters() -> [UniqueCharacter]{
let array: [Character] = Array(self)
return array.uniqueCharacters()
}
func numberOnly() -> String {
self.trimmingCharacters(in: CharacterSet(charactersIn: "-0123456789.").inverted)
}
}
extension Array where Element == Character {
func uniqueCharacters() -> [UniqueCharacter]{
var array: [UniqueCharacter] = []
for char in self{
array.append(UniqueCharacter(char: char))
}
return array
}
}
//String/Characters can be repeating so yu have to make them a unique value
struct UniqueCharacter: Identifiable, Equatable, Hashable{
var char: Character
var id: UUID = UUID()
}
#available(iOS 15.0, *)
struct PinView_Previews: PreviewProvider {
static var previews: some View {
PinParentView()
}
}