Search code examples
iosswiftswiftuipicker

How SwiftUI onChange modifier works?


I populated a SwiftUI Picker dynamically. The Picker is working successfully. I want to trigger or listen picker changing event. Suppose I will print the value if an user select an item. My iOS deployment target is 14, I found that iOS has an inbuilt function onChange to detect this kind of listener. I used that modifier but not working. Here is my code:

var body: some View {
    
    
    
    Picker( selection: $selectedStrength, label: Text("Status")) {
        
        ForEach(courseList, id: \.self) { item in
            
            Text(item.courseCode ?? "")
        }
    }
    .onChange(of:selectedStrength, perform: { _ in
        
        print("Value Changed!")
        
    })
    .pickerStyle(WheelPickerStyle())
    
}

Solution

  • Summery: I called a REST API and parse the data, then I tried to create a SwiftUI Picker from those data.

    Solution: After searching a lot, I found the right solution. I was populating the Picker directly from Json object data. I converted those data into SwiftUI string array and tried onChange function, its working now.

    My Code :

    import SwiftUI
    
    struct TeacherCourseListParser: Decodable, Hashable{
        
        var totalStudent: Int?
        var courseName: String?
        var courseCode: String?
        var courseId: Int?
        var courseTeacherEnrollId: Int?
        
        
    }
    
    
        
    
    struct Test: View {
        
        @State var courseList = [TeacherCourseListParser]()
              
        @State private var selectedStrength = ""
        @State var courseCodeTempArray = [String]()
        
        var body: some View {
            
            VStack(spacing: 0){
                
                
                Picker( selection: $selectedStrength, label: Text("Course Code")) {
                    
                    ForEach(courseCodeTempArray, id: \.self) {
                        
                       
                        Text($0)
                        
                        
                    }
                }
                .onChange(of: selectedStrength, perform: { _ in
                    
                    print("Value Changed!")
                })
                .pickerStyle(WheelPickerStyle())
                
                
                
                
                
            }
            
        }
    

    Here is the function how I fetched the JSON object :

    func FetchTeacherCourseCode(){
            
            
            
            
            let token = UserDefaults.standard.string(forKey: "login_token")
          
            
            // create post request
                                                          
            guard let url = URL(string: Constant.mainServerUrl+Constant.getTeacherCourseList) else {
                print("Invalid URL")
                return
            }
            
            print(url)
            
            var request = URLRequest(url: url)
            request.httpMethod = "GET"
            // request.httpBody = jsonData
            request.allHTTPHeaderFields = [
                "Content-Type": "application/json",
                "Accept": "application/json",
                "Authorization": "Bearer "+token!
            ]
            
            URLSession.shared.dataTask(with: request) {data, response, error in
                if let data = data {
                    do {
                                                                                            
                        //-- Parse response according to the object
                        let detailedObjectFetcher = try! JSONDecoder().decode([TeacherCourseListParser].self, from: data)
                       
                        
                                                                        
                        DispatchQueue.main.async {
                            
                            for i in detailedObjectFetcher {
                                
                                // instead of populating Picker from JSON object directly I generated a string array                                                     
                                courseCodeTempArray.append(i.courseCode ?? "")
                                
                            }
                            
                           self.courseList = detailedObjectFetcher
                            showProgressBar = false
                            
                            
                        }
                        
                        
                        
                        
                    } catch DecodingError.keyNotFound(let key, let context) {
                        Swift.print("could not find key \(key) in JSON: \(context.debugDescription)")
                    } catch DecodingError.valueNotFound(let type, let context) {
                        Swift.print("could not find type \(type) in JSON: \(context.debugDescription)")
                    } catch DecodingError.typeMismatch(let type, let context) {
                        Swift.print("type mismatch for type \(type) in JSON: \(context.debugDescription)")
                    } catch DecodingError.dataCorrupted(let context) {
                        Swift.print("data found to be corrupted in JSON: \(context.debugDescription)")
                    } catch let error as NSError {
                        NSLog("Error in read(from:ofType:) domain= \(error.domain), description= \(error.localizedDescription)")
                    }
                }
                // print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
                
            }.resume()
            
            
            
        }
    }