Swift入门咨询:编码与解码差异及JSONDecoder解析嵌套JSON
Hey there! Let's break this down step by step since you're new to Swift 😊
First: Encoding vs Decoding - Key Differences
Let's keep this simple:
- Decoding: This is taking external data (like JSON from an API) and converting it into Swift-native types (structs/classes) that your code can work with. That's exactly what you're doing right now—turning the API's JSON response into your
GenderandResultstructs. - Encoding: The reverse process. You take Swift structs/classes and convert them into a format that can be sent outside your app (like JSON to send to an API). You'd use
JSONEncoderfor this, for example when submitting user data to a backend.
Second: Finishing the JSON Parsing & Adding to a Picker
Let's complete your code and get those gender categories into a Picker. I'll assume you're using SwiftUI (the most common approach these days), but I'll also note how to adapt this for UIKit if needed.
Step 1: Fix the Decoding Logic & Manage Data
First, let's finish your network call and set up a way to store the gender options so your UI can react to changes:
// Keep your Gender struct (I simplified it a bit—you don't need a separate CodingKeys enum for the top-level Gender unless you're renaming fields) struct Gender: Decodable { let result: [Result] struct Result: Decodable { let genderCategory: String // This maps the snake_case JSON key to your camelCase Swift property enum CodingKeys: String, CodingKey { case genderCategory = "gender_category" } } } // Use an ObservableObject to manage your data (so the UI updates when data loads) class GenderViewModel: ObservableObject { // Published property tells SwiftUI to refresh the UI when this changes @Published var genderOptions: [String] = [] func getGenderValueFromJSON() { // Safely unwrap the URL first (avoid force-unwrapping with !) guard let url = URL(string: "http://www.----------.com/GenderList/get") else { print("Oops, invalid URL!") return } URLSession.shared.dataTask(with: url) { [weak self] data, response, error in // Handle network errors first if let error = error { print("Network error: \(error.localizedDescription)") return } // Make sure we actually got data back guard let responseData = data else { print("No data received from the API") return } do { // Decode the JSON into your Gender struct let genderResponse = try JSONDecoder().decode(Gender.self, from: responseData) // Extract all the gender_category values into a simple array let categoryList = genderResponse.result.map { $0.genderCategory } // Update the UI on the MAIN THREAD (network calls run in background!) DispatchQueue.main.async { self?.genderOptions = categoryList } } catch { print("Decoding failed: \(error.localizedDescription)") } }.resume() } }
Step 2: Build the Picker in SwiftUI
Now let's create a view that uses this ViewModel to display the Picker:
struct GenderPickerView: View { // Create an instance of our ViewModel @StateObject private var viewModel = GenderViewModel() // Track the user's selected gender @State private var selectedGender = "" var body: some View { VStack(spacing: 20) { Text("Select a Gender Category") .font(.headline) // The Picker itself Picker("Gender Category", selection: $selectedGender) { // Loop through our loaded gender options ForEach(viewModel.genderOptions, id: \.self) { category in Text(category).tag(category) } } .pickerStyle(.wheel) // Change to .menu or .inline if you prefer .padding() // Show the selected value Text("Selected: \(selectedGender.isEmpty ? "None" : selectedGender)") } .onAppear { // Load data when the view first appears viewModel.getGenderValueFromJSON() } } }
If You're Using UIKit Instead:
If you're working with UIKit, here's a quick outline:
- In your
UIViewController, declarevar genderOptions: [String] = []and aUIPickerViewoutlet. - Make your view controller conform to
UIPickerViewDataSourceandUIPickerViewDelegate. - After decoding the JSON, update
genderOptionsand callpickerView.reloadAllComponents(). - Implement the required delegate methods:
func numberOfComponents(in pickerView: UIPickerView) -> Int { 1 } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { genderOptions.count } func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { genderOptions[row] }
Quick Notes to Keep in Mind:
- Double-check that your API's JSON structure matches your
Genderstruct. It should look something like this:{ "result": [ {"gender_category": "Male"}, {"gender_category": "Female"}, {"gender_category": "Non-binary"} ] } - Always handle errors (network issues, invalid data, decoding failures) instead of ignoring them—it'll save you headaches later!
- Never update UI from a background thread (that's why we use
DispatchQueue.main.asyncin the network callback).
内容的提问来源于stack exchange,提问作者TheSwiftGuy77




