使用Swift讀取JSON檔案


在本文中,我們將瞭解一些使用JSONSerialization和JSONDecoder類讀取JSON檔案的示例。如今,大多數iOS應用程式都使用這些類來處理JSON檔案。

您可以使用JSONSerialization類在Swift語言中讀取JSON檔案。為了讀取json檔案,首先需要將其轉換為字串或資料物件。之後,您可以將字串或資料物件傳遞給JSONSerialization類,將其轉換為字典或陣列物件。

JSONSerialization

iOS和macOS的Foundation框架預設包含JSONSerialization類。要建立Swift字典或陣列,此類需要字串或資料物件。使用相同的類,您還可以將字典或陣列轉換為JSON物件。JSONSerialization類處理序列化和反序列化過程。

此類的主要函式jsonObject(with:options:)用於反序列化,或將JSON資料轉換為Swift物件。此方法需要一個包含JSON資料的資料物件,以及一個名為options的引數,該引數控制方法的行為。此方法返回一個Swift物件,該物件可以是陣列或字典。JSON資料格式將決定返回型別。

以下是如何讀取JSON檔案並將其解析為字典的示例:

使用JSONSerialization類讀取JSON

這是一個JSON示例:

示例

{
   "id": 1,
   "title": "iPhone 12",
   "price": 749,
   "thumbnail": "https://i.dummyjson.com/data/products/1/thumbnail.jpg",
   "manufacturedDetail": {
      "company": {
         "manufacturedBy": "Apple Inc."
      }
   }
}

我們將使用上面的JSON來讀取它。您可以透過為檔案命名,向Xcode專案新增一個副檔名為“.json”的新檔案。

讀取JSON檔案

func readJSONFile(forName name: String) {
   do {
      if let bundlePath = Bundle.main.path(forResource: name, ofType: "json"),
      let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) {           
         if let json = try JSONSerialization.jsonObject(with: jsonData, options: .mutableLeaves) as? [String: Any] {
            print("JSON: \(json)")
         } else {
            print("Given JSON is not a valid dictionary object.")
         }
      }
   } catch {
      print(error)
   }
}

輸出

JSON: ["title": iPhone 12, "price": 749, "thumbnail": https://i.dummyjson.com/data/products/1/thumbnail.jpg, "id": 1, "manufacturedDetail": {
   company =     {
      manufacturedBy = "Apple Inc.";
   };
}]

這將為您提供一個JSON物件,您可以在程式碼中將其用作字典。如果您的JSON檔案是物件的陣列,則可以使用mutableContainers選項而不是mutableLeaves。由於我們必須從JSON物件讀取字典,因此我們將使用mutableLeaves選項。

使用JSONDecoder()類讀取JSON

Swift的新版本引入了Codable協議,這使得使用起來更加容易和靈活。

然後使用JSONDecoder類將檔案中的JSON資料解析為給定型別的例項(類或結構)。decode(_:from:)方法用於反序列化JSON資料,然後返回生成的Type物件以訪問Type物件的屬性。

我們正在嘗試使用Codable協議讀取上面給出的相同JSON作為示例。在我們準備好使用JSONDecoder()類解碼JSON資料之前,讓我們準備在解碼時提供的模型類。

根據上面的JSON資料,這是模型類:

import Foundation
struct Product: Decodable {  
   let id: Int
   let title: String
   let price: Int
   let thumbnail: String
   let manufacturedBy: String
    
   enum RootKeys: String, CodingKey {
      case id, title, price, thumbnail, manufacturedDetail
   }
    
   enum ManufacturedKeys: String, CodingKey {
      case company
   }
    
   enum CompanyKeys: String, CodingKey {
      case manufacturedBy
   }
   
   init(from decoder: Decoder) throws {
      let values = try decoder.container(keyedBy: RootKeys.self)
      id = try values.decode(Int.self, forKey: .id)
      title = try values.decode(String.self, forKey: .title)
      price = try values.decode(Int.self, forKey: .price)
      thumbnail = try values.decode(String.self, forKey: .thumbnail)
        
      let manufacturedContainer = try values.nestedContainer(keyedBy: ManufacturedKeys.self, forKey: .manufacturedDetail)
      let companyContainer = try manufacturedContainer.nestedContainer(keyedBy: CompanyKeys.self, forKey: .company)
      self.manufacturedBy = try companyContainer.decode(String.self, forKey: .manufacturedBy)
   }
}

如何解碼?

func readJSONFile(forName name: String) {
   do {  
   
      // creating a path from the main bundle and getting data object from the path
      if let bundlePath = Bundle.main.path(forResource: name, ofType: "json"),
      let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) {
            
         // Decoding the Product type from JSON data using JSONDecoder() class.
         let product = try JSONDecoder().decode(Product.self, from: jsonData)
         print("Product name: \(product.title) and its price: \(product.price)")
      }
   } catch {
      print(error)
   }
}

輸出

Product name: iPhone 12 and its price: 749

結論

在Swift中,您可以透過低階API將原始JSON資料轉換為陣列或字典之類的集合。您可以使用JSONSerialization類將原始JSON物件轉換為有意義的物件。此類內置於Foundation框架中。您可以在任何平臺(例如iOS、macOS、watchOS等)上使用此類。此外,反過來,您可以使用反序列化過程將自定義物件轉換回原始JSON資料。

在Swift 4中,Apple引入了Codable協議,該協議使序列化和反序列化過程變得容易。此協議提供了一種靈活的方式來使用JSON資料來解析資料並將其儲存到模型類/結構中。此協議可用於輕鬆地將模型物件轉換為JSON資料。

Codable協議有助於減少程式碼並處理序列化和反序列化過程,使程式碼更簡潔易維護。

更新於:2023年2月28日

11K+ 次瀏覽

啟動您的職業生涯

完成課程獲得認證

開始學習
廣告