Swift下將網路返回json資料轉換成struct
假如網路請求返回的資料結構是一個深層巢狀的Json
首先要透過key-value取出這個json中的資料來源
// 將返回的json字串轉Dictory let json = """ { "name": "jack", "age": 20, "description": "A student." } """.data(using: .utf8)! if let jsonData = jsonString.data(using: .utf8) { do { let json = try JSONSerialization.jsonObject(with: jsonData, options: []) if let dictionary = json as? [String: Any], let key2 = dictionary["key2"] as? [String: Any], let innerKey2 = key2["key2"] as? [String: Any], let value = innerKey2["key1"] as? String { print(value) // 輸出"value3" } } catch { print("解析JSON資料失敗:(error)") } }
數模轉換
// 定義資料型別,遵守Codable協議 // 注意定義的型別與介面返回對應,否則JSONSerialization時崩潰 // Struct模型可以根據json中的資料關係對應巢狀 struct ContactSimpleModel: Codable { var relation: String var name: String struct ContactSimpleModel1: Codable { var relation: String var name: String struct ContactSimpleModel2: Codable { var relation: String var name: String } } }
字典與struct互相轉換
將字典轉換成struct模型
根據網路返回的Dictory,從裡面取出陣列widgets: Array<[String: Any]>
1.map遍歷陣列,拿到每一個陣列元素字典
2.處理每個元素,先使用JSONSerialization.data(withJSONObject:將字典轉成data,
3.再使用JSONDecoder().decode(ContactSimpleModel.self, from: data)將data轉成struct結構體。
4.使用struct模型
let decoder = JSONDecoder() let resList = try widgets.map { (item) -> AdJsonModel in let data = try JSONSerialization.data(withJSONObject: item, options: []) let res = try decoder.decode(AdJsonModel.self, from: data) return res } return resList
struct模型轉字典
也可以透過給Encodable協議加預設實現,提供便捷Struct轉字典方法
// 擴充套件 Encodable 協議 extension Encodable { var dictionary: [String: Any]? { if let data = try? JSONEncoder().encode(self) { if let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] { return dict } return nil } return nil } }
Struct本地快取
假如沒有使用資料庫,透過UserDefaults或者Plist檔案儲存。
使用data進行儲存到UserDefaults
struct Person: Codable { var name: String var age: Int } var people = [Person(name: "John", age: 30), Person(name: "Mary", age: 25)] //轉成data儲存 let data = try! JSONEncoder().encode(people) UserDefaults.standard.set(data, forKey: "peopleData") //取 if let data = UserDefaults.standard.data(forKey: "peopleData") { let people = try! JSONDecoder().decode([Person].self, from: data) }
使用Dictionary儲存到Plist檔案
本地檔案處理
路徑判斷,建立目錄用Url.path
建立目錄案例
lazy var adListDirPath: String? = { let documentDic = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first let adUrl = documentDic?.appendingPathComponent(":ad") if let adUrlSub = adUrl { var isDic: ObjCBool = ObjCBool(false) // 判斷adUrlSub.path路徑是否存在,如果是檔案路徑則isDic=false, 如果是目錄路徑isDic=true if FileManager.default.fileExists(atPath: adUrlSub.path, isDirectory: &isDic) && isDic.boolValue { return adUrlSub.absoluteString } do { // 如果路徑不存在,則建立本地路徑,withIntermediateDirectories: true表示如果路徑中間有未建立的,則把中間的目錄也建立 try FileManager.default.createDirectory(at: adUrlSub, withIntermediateDirectories: true, attributes: nil) return adUrlSub.absoluteString } catch { Logger.error(":adDataManager", content: error.localizedDescription) return nil } } return nil }()
寫檔案要用Url.absoluteString
swift中儲存plist檔案,使用NSDictionary進行儲存
1.先刪除歷史檔案 do { try FileManager.default.removeItem(at: filePathUrl) return true } catch { Logger.error(":adDataManager", content: error.localizedDescription) return false } 2.儲存新檔案 NSDictionary(object: adList, forKey: adListRootKey).write(to: filePathUrl, atomically: true) 3.讀取本地檔案 let dict = try NSDictionary(contentsOf: filePathUrl, error: ())
zip檔案解壓
func unzipFile() { let zipPath = "/path/to/zip/file" let destinationPath = "/path/to/destination/folder" do { try ZipArchive.unzipFile(atPath: zipPath, toDestination: destinationPath) } catch { print("Error unzipping file: (error.localizedDescription)") } }
先快取後使用,提高使用者體驗
SDWebImage的先預下載圖片,等啟動時直接使用快取的方法
//0.自定義設定快取大小 URLCache.shared = URLCache(memoryCapacity: 10 * 1024 * 1024, diskCapacity: 50 * 1024 * 1024, diskPath: nil) //1.快取 SDWebImage批次下載圖片 SDWebImagePrefetcher.shared().prefetchURLs方法下載的圖片本地路徑預設是Library/Caches/com.hackemist.SDWebImageCache.default目錄下的快取檔案。 可以透過SDWebImageManager.shared().imageCache.diskCachePath方法獲取具體路徑。 //2.使用 在UIImageView載入圖片時,使用AAImageView.sd_setImage(with: url, placeholderImage: nil)進行價值
注意:
對於可選型別的陣列,如果沒有拆包就map, 那麼閉包的入參是拆包的陣列
let list = dict[adListRootKey] as? Array<[String: Any]> if let listSub = list { let decoder = JSONDecoder() let resList = listSub.map { (item) -> AdJsonModel? in