You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI新手求助:本地JSON解析至ListView失败

Hey there! Let's break down what's going wrong with your JSON parsing in SwiftUI and fix it step by step. The core issue is a mismatch between your data model and the actual structure of your JSON, plus a few small syntax/logic errors in your code.


Key Problems in Your Current Code

  1. Incorrect sentence type: Your JSON's sentence field isn't a string—it's a nested dictionary of key-value pairs (like sentence1: "I eat the apple"). Defining it as String in your models is why parsing fails.
  2. CodingKeys mismatch: In your second attempt, you mapped name to "language" in CodingKeys, but your JSON uses "name" for that field.
  3. ObservableObject usage error: In ContentView, you tried to use TwelveData (your model) as an @ObservedObject instead of your TwelveSentences data loader class.
  4. Unsafe try in DispatchQueue: Your second attempt's DispatchQueue.main.async block contains a try without a do-catch wrapper, which will cause a runtime error.

Fixed Solution

Let's rewrite everything to match your JSON structure properly:

1. Correct Data Model

We'll use a dictionary for sentence to handle the dynamic keys (like sentence1, sentence1a), and add a computed property to sort the sentences logically:

import SwiftUI
import Foundation

struct LanguageData: Codable, Identifiable {
    let id: Int
    let name: String
    let sentence: [String: String] // Matches the nested JSON object
    
    // Computed property to sort sentences by number + suffix (e.g., sentence1 < sentence1a < sentence2)
    var sortedSentences: [(key: String, value: String)] {
        sentence.sorted {
            let key1 = $0.key.replacingOccurrences(of: "sentence", with: "")
            let key2 = $1.key.replacingOccurrences(of: "sentence", with: "")
            
            // Sort by numeric part first, then alphabetical suffix
            if let num1 = Int(key1.filter(\.isNumber)), let num2 = Int(key2.filter(\.isNumber)) {
                if num1 != num2 {
                    return num1 < num2
                } else {
                    return key1 < key2
                }
            }
            return key1 < key2
        }
    }
}

2. Data Loader Class

Clean up the loading logic with proper error handling and no unnecessary main thread dispatch (JSON parsing doesn't need to run on the main thread, and @Published will handle UI updates automatically):

class LanguageDataLoader: ObservableObject {
    @Published var languages = [LanguageData]()
    
    init() {
        loadData()
    }
    
    private func loadData() {
        guard let fileURL = Bundle.main.url(forResource: "twelveData", withExtension: "json") else {
            print("Error: Could not find twelveData.json in the app bundle")
            return
        }
        
        do {
            let data = try Data(contentsOf: fileURL)
            let decodedLanguages = try JSONDecoder().decode([LanguageData].self, from: data)
            // Sort languages by ID to match your original intent
            self.languages = decodedLanguages.sorted { $0.id < $1.id }
        } catch {
            print("JSON Parsing Error: \(error.localizedDescription)")
            print("Full error details: \(error)")
        }
    }
}

3. Content View

Use the data loader correctly, and display the sentences in a structured, readable way:

struct ContentView: View {
    @ObservedObject var dataLoader = LanguageDataLoader()
    
    var body: some View {
        // Use NavigationStack for iOS 16+ (replace with NavigationView for older versions)
        NavigationStack {
            List(dataLoader.languages) { language in
                Section(header: Text(language.name).font(.title2).bold()) {
                    ForEach(language.sortedSentences, id: \.key) { sentence in
                        VStack(alignment: .leading) {
                            Text(sentence.key)
                                .font(.caption)
                                .foregroundColor(.secondary)
                            Text(sentence.value)
                                .font(.body)
                                .padding(.top, 2)
                        }
                    }
                }
            }
            .navigationTitle("Language Sentences")
            .listStyle(.insetGrouped)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Final Notes

  • Make sure your twelveData.json file has its Target Membership checked (select the file in Xcode, then check your app's target in the right sidebar). This ensures it's included in the app bundle.
  • The sortedSentences property ensures your sentences display in logical order (not random dictionary order), which is crucial for readability.

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 12:37:51