簡體   English   中英

JSON 解析錯誤 - 沒有與鍵 CodingKeys 關聯的值

[英]JSON parsing error - No value associated with key CodingKeys

所以,我試着尋找答案,我看到了很多和我類似的問題。 我試過添加一個枚舉codingKey,我試過修改JSON,但似乎沒有任何效果。 我知道這可能也很簡單。 (我是菜鳥。)請幫忙。

我正在制作一個 Quotes 應用程序,作為我正在學習的課程項目的一部分。

這是 Model 的代碼:

import Foundation

class AllQuotes: Identifiable, Decodable {
    
    var id:UUID?
    var quoteTopic:String
    var topicImage:String
    var featured:Bool
    var QuotesList:[Quotes]
}

class Quotes: Identifiable, Decodable {
    var id:UUID?
    var name:String
    var actualQuote:String
    var image:String?
    
    private enum CodingKeys: String, CodingKey {
        case id = "id"
        case name = "name"
        case actualQuote = "actualQuote"
        case image = "image"
    }
}

這是我的 JSON 代碼:

[
  {
    "quoteTopic": "Wise Quotes",
    "topicImage": "wise quotes",
    "featured": false,
    "QuotesList": [
      {
        "name": "Lao Tzu",
        "actualQuote": "The journey of a thousand miles begins with one step.",
        "image": null
      },
      {
        "name": "Mark Twain",
        "actualQuote": "It is better to keep your mouth closed and let people think you are a fool than to open it and remove all doubt.",
        "image": null
      },
      {
        "name": "Mark Twain",
        "actualQuote": "The secret of getting ahead is getting started.",
        "image": null
      },
      {
        "name": "Babe Ruth",
        "actualQuote": "It’s hard to beat a person who never gives up.",
        "image": null
      }
    ]
  },
  {
    "quoteTopic": "Motivational Quotes",
    "topicImage": "motivational quotes",
    "featured": true,
    "QuotesList": [
      {
        "name": "Mark Twain",
        "actualQuote": "Age is an issue of mind over matter. If you don't mind, it doesn't matter.",
        "image": null
      },
      {
        "name": "Mahatma Gandhi",
        "actualQuote": "Learn as if you will live forever, live like you will die tomorrow.",
        "image": null
      },
      {
        "name": "Mary Kay Ash",
        "actualQuote": "Don’t limit yourself. Many people limit themselves to what they think they can do. You can go as far as your mind lets you. What you believe, remember, you can achieve.",
        "image": null
      },
      {
        "name": "Unknown",
        "actualQuote": "Hold the vision, trust the process.",
        "image": null
      }
    ]
  },
  {
    "quoteTopic": "Success Quotes",
    "topicImage": "success quotes",
    "featured": false,
    "QuotesList": [
      {
        "name": "Estee Lauder",
        "actualQuote": "I never dreamed about success. I worked for it.",
        "image": null
      },
      {
        "name": "Thomas Edison",
        "actualQuote": "Opportunity is missed by most people because it is dressed in overalls and looks like work.",
        "image": null
      },
      {
        "name": "Tom Lehrer",
        "actualQuote": "Life is like a sewer… what you get out of it depends on what you put into it.",
        "image": null
      },
      {
        "name": "Walt Disney",
        "actualQuote": "All our dreams can come true, if we have the courage to pursue them.",
        "image": null
      }
    ]
  }
]

這是我得到的錯誤

無法解碼 json,重試(獲取實際報價):keyNotFound(CodingKeys(stringValue, "name": intValue, nil). Swift.DecodingError:Context(codingPath: [_JSONKey(stringValue, "Index 0": intValue) , 0)]: debugDescription: "No value associated with key CodingKeys(stringValue, "name": intValue.nil) ("name"),": underlyingError: nil))

(注意:它運行/構建正常,但當我嘗試運行它時它不會顯示“QuotesDetailView”頁面。它是 SwiftUI。

如果我需要提供更多信息,請告訴我,謝謝!

編輯:這是我解碼 JSON 的方法

class DataService {
    
    // Return an array of Quote Objects
    static func getLocalData() -> [AllQuotes] {
        // Begin the process of parsing the JSON File
        
        // Get a URL path to json file
        let pathString = Bundle.main.path(forResource: "quotes", ofType: "json")
        
        // Check if pathString is nil, otherwise return empty Quotes List if it is.
        guard pathString != nil else{
            return [AllQuotes]()
        }
        
        // Create URL Object
        let url = URL(fileURLWithPath: pathString!)
        
        // Create Data Object
        do {
            let data = try Data(contentsOf: url)
            
            // Parse the data
            let decoder = JSONDecoder()
            
            do {
                let quoteData = try decoder.decode([AllQuotes].self, from: data)
                
                // Set unique IDs for each instance
                for newQuote in quoteData {
                    newQuote.id = UUID()
                }
                
                // Return the Quote
                return quoteData
            
            } catch {
                // Couldn't decode json
                print("Couldn't decode json, try again (to get the quotes TOPIC)!")
                print(error)
            }
            
        } catch {
            // Error fetching data from file
            print("There was an error fetching the data from the file. - with the quote list!")
            print(error)
        }
        
        // It didn't work, return an empty Quotes List
        return [AllQuotes]()
    }
    
    // Return an array of ACTUAL Quotes Objects
    static func getActualQuote() -> [Quotes] {
        // Begin the process of parsing the JSON File
        
        // Get a URL path to json file
        let pathString = Bundle.main.path(forResource: "quotes", ofType: "json")
        
        // Check if pathString is nil, otherwise return empty Quotes List if it is.
        guard pathString != nil else{
            return [Quotes]()
        }
        
        // Create URL Object
        let url = URL(fileURLWithPath: pathString!)
        
        // Create Data Object
        do {
            let data = try Data(contentsOf: url)
            
            // Parse the data
            let decoder = JSONDecoder()
            
            do {
                
                let actualQuoteData = try decoder.decode([Quotes].self, from: data)
                
                // Set unique IDs for each instance
                for actualQuote in actualQuoteData {
                    actualQuote.id = UUID()
                }
                
                // Return the Quote
                return actualQuoteData
            
            } catch {
                // Couldn't decode json
                print("Couldn't decode json, try again (to get the actual quote)!")
                print(error)
            }
            
            
        } catch {
            // Error fetching data from file
            print("There was an error fetching the data from the file. - with the actual quote!")
            print(error)
        }
        
        // It didn't work, return an empty Quotes List
        return [Quotes]()
    }
    
    
}

試試這個示例代碼,它展示了如何解碼您的 json 數據,然后顯示一些信息:

由於您沒有展示如何解碼 json 數據,我猜您得到的錯誤是由於解碼AllQuotes.self而不是[AllQuotes].self根據需要。

struct ContentView: View {
    @State var quoteList = [Quotes]()
    
    var body: some View {
        List(quoteList) { quote in
            Text(quote.name)
        }
        .onAppear {
           let json = """
[
  {
    "quoteTopic": "Wise Quotes",
    "topicImage": "wise quotes",
    "featured": false,
    "QuotesList": [
      {
        "name": "Lao Tzu",
        "actualQuote": "The journey of a thousand miles begins with one step.",
        "image": null
      },
      {
        "name": "Mark Twain",
        "actualQuote": "It is better to keep your mouth closed and let people think you are a fool than to open it and remove all doubt.",
        "image": null
      },
      {
        "name": "Mark Twain",
        "actualQuote": "The secret of getting ahead is getting started.",
        "image": null
      },
      {
        "name": "Babe Ruth",
        "actualQuote": "It’s hard to beat a person who never gives up.",
        "image": null
      }
    ]
  },
  {
    "quoteTopic": "Motivational Quotes",
    "topicImage": "motivational quotes",
    "featured": true,
    "QuotesList": [
      {
        "name": "Mark Twain",
        "actualQuote": "Age is an issue of mind over matter. If you don't mind, it doesn't matter.",
        "image": null
      },
      {
        "name": "Mahatma Gandhi",
        "actualQuote": "Learn as if you will live forever, live like you will die tomorrow.",
        "image": null
      },
      {
        "name": "Mary Kay Ash",
        "actualQuote": "Don’t limit yourself. Many people limit themselves to what they think they can do. You can go as far as your mind lets you. What you believe, remember, you can achieve.",
        "image": null
      },
      {
        "name": "Unknown",
        "actualQuote": "Hold the vision, trust the process.",
        "image": null
      }
    ]
  },
  {
    "quoteTopic": "Success Quotes",
    "topicImage": "success quotes",
    "featured": false,
    "QuotesList": [
      {
        "name": "Estee Lauder",
        "actualQuote": "I never dreamed about success. I worked for it.",
        "image": null
      },
      {
        "name": "Thomas Edison",
        "actualQuote": "Opportunity is missed by most people because it is dressed in overalls and looks like work.",
        "image": null
      },
      {
        "name": "Tom Lehrer",
        "actualQuote": "Life is like a sewer… what you get out of it depends on what you put into it.",
        "image": null
      },
      {
        "name": "Walt Disney",
        "actualQuote": "All our dreams can come true, if we have the courage to pursue them.",
        "image": null
      }
    ]
  }
]
"""
                if let data = json.data(using: .utf8) {
                    do {
                        let apiResponse = try JSONDecoder().decode([AllQuotes].self, from: data)
                        // print something
                        for quote in apiResponse {
                            print("---> quoteTopic: \(quote.quoteTopic)")
                            // all quotes
                            quoteList.append(contentsOf: quote.QuotesList)
                        }
                    } catch {
                        print("decode error: \(error)")
                    }
                }
                 
            }
    }
    
}

class AllQuotes: Identifiable, Decodable {
    let id = UUID()  // <-- here
    var quoteTopic:String
    var topicImage:String
    var featured:Bool
    var QuotesList:[Quotes]
    
    // -- here
    private enum CodingKeys: String, CodingKey {
        // <-- here remove id
        case quoteTopic, topicImage, featured, QuotesList
    }
}

class Quotes: Identifiable, Decodable {
    let id = UUID() // <-- here
    var name:String
    var actualQuote:String
    var image:String?
    
    // -- here
    private enum CodingKeys: String, CodingKey {
        // <-- here remove id
        case name = "name"
        case actualQuote = "actualQuote"
        case image = "image"
    }
}

EDIT-1:鑒於“新”代碼

struct ContentView: View {
    @State var quoteList = [Quotes]()
    
    var body: some View {
        List(quoteList) { quote in
            Text(quote.name)
        }
        .onAppear {
            quoteList = DataService.getActualQuote()
            print("---> quoteList: \(quoteList)")
        }
    }
}

class DataService {
    
    // Return an array of Quote Objects
    static func getLocalData() -> [AllQuotes] {
        // Begin the process of parsing the JSON File
        
        // Get a URL path to json file
        let pathString = Bundle.main.path(forResource: "quotes", ofType: "json")
        
        // Check if pathString is nil, otherwise return empty Quotes List if it is.
        guard pathString != nil else{
            return [AllQuotes]()
        }
        let url = URL(fileURLWithPath: pathString!)
        do {
            let data = try Data(contentsOf: url)
            do {
                let quoteData = try JSONDecoder().decode([AllQuotes].self, from: data)
                return quoteData
            } catch {
                // Couldn't decode json
                print("Couldn't decode json, try again (to get the quotes TOPIC)!")
                print(error)
            }
        } catch {
            // Error fetching data from file
            print("There was an error fetching the data from the file. - with the quote list!")
            print(error)
        }
        
        // It didn't work, return an empty Quotes List
        return []
    }
    
    // Return an array of ACTUAL Quotes Objects
    static func getActualQuote() -> [Quotes] {
        // Begin the process of parsing the JSON File
        
        // Get a URL path to json file
        let pathString = Bundle.main.path(forResource: "quotes", ofType: "json")
        
        // Check if pathString is nil, otherwise return empty Quotes List if it is.
        guard pathString != nil else{
            return [Quotes]()
        }
        
        // Create URL Object
        let url = URL(fileURLWithPath: pathString!)
        
        // Create Data Object
        do {
            let data = try Data(contentsOf: url)
            do {
                // -- here
                let quoteData = try JSONDecoder().decode([AllQuotes].self, from: data)
                // -- here
                var actualQuoteData = [Quotes]()
                for quote in quoteData {
                    actualQuoteData.append(contentsOf: quote.QuotesList)
                }
                // Return the Quotes
                return actualQuoteData
            } catch {
                // Couldn't decode json
                print("Couldn't decode json, try again (to get the actual quote)!")
                print(error)
            }
        } catch {
            // Error fetching data from file
            print("There was an error fetching the data from the file. - with the actual quote!")
            print(error)
        }
        
        // It didn't work, return an empty Quotes List
        return []
    }

}

EDIT-2:您可以縮短代碼,例如:

class DataService {
    
    // Return an array of Quote Objects
    static func getLocalData() -> [AllQuotes] {
        if let pathString = Bundle.main.path(forResource: "quotes", ofType: "json") {
            let url = URL(fileURLWithPath: pathString)
            do {
                let data = try Data(contentsOf: url)
                let quoteData = try JSONDecoder().decode([AllQuotes].self, from: data)
                return quoteData
            } catch {
                print(error)
            }
        }
        return []
    }
    
    // Return an array of ACTUAL Quotes Objects
    static func getActualQuote() -> [Quotes] {
        var actualQuoteData = [Quotes]()
        for quote in getLocalData() {
            actualQuoteData.append(contentsOf: quote.QuotesList)
        }
        return actualQuoteData
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM