You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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 Gender and Result structs.
  • 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 JSONEncoder for 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:

  1. In your UIViewController, declare var genderOptions: [String] = [] and a UIPickerView outlet.
  2. Make your view controller conform to UIPickerViewDataSource and UIPickerViewDelegate.
  3. After decoding the JSON, update genderOptions and call pickerView.reloadAllComponents().
  4. 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 Gender struct. 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.async in the network callback).

内容的提问来源于stack exchange,提问作者TheSwiftGuy77

火山引擎 最新活动