Swift下Data處理全流程:從網絡下載,數模轉換,本地緩存到頁面使用

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

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章