• Swift下Data处理全流程:从网络下载,数模转换,本地缓存到页面使用


    Swift下将网络返回json数据转换成struct
    假如网络请求返回的数据结构是一个深层嵌套的Json
    首先要通过key-value取出这个json中的数据源
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 将返回的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)")
        }
    }
    数模转换
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 定义数据类型,遵守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模型
    1
    2
    3
    4
    5
    6
    7
    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转字典方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 扩展 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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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
    创建目录案例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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文件解压
    1
    2
    3
    4
    5
    6
    7
    8
    9
      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的先预下载图片,等启动时直接使用缓存的方法
    1
    2
    3
    4
    5
    6
    7
    8
    //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)进行价值 
    1
    2
    //3.删除缓存
    SDWebImageManager.shared.imageCache.removeImage(forKey: $0, cacheType: SDImageCacheType.all)

     

     
    注意:
    对于可选类型的数组,如果没有拆包就map, 那么闭包的入参是拆包的数组
    1
    2
    3
    4
    let list = dict[adListRootKey] as? Array<[String: Any]>
    if let listSub = list {
        let decoder = JSONDecoder()
        let resList = listSub.map { (item) -> AdJsonModel? in

     

     

     

     

     

  • 相关阅读:
    架构的未来——End
    【四】设计模式~~~创建型模式~~~建造者模式(Java)
    AIGC——ComfyUI 安装与基础使用
    delete删除后怎么恢复文件?四种方法进行找回
    Python中文分词及词频统计
    Unity 在子线程中调用主线程的方法
    MYSQLg高级------回表
    油溶性CdTe/CdSe/ZnS量子点 发光颜色:高亮红光
    关于 Kafka 你必须知道的知识点(图文详解)
    【Chain of Resposibility】C++设计模式——职责链
  • 原文地址:https://www.cnblogs.com/zhou--fei/p/17372535.html