【问题标题】:JSON, Codable, Image, trying to encode array of struct that include image by converting image to base64JSON,可编码,图像,尝试通过将图像转换为 base64 来编码包含图像的结构数组
【发布时间】:2021-09-15 04:42:06
【问题描述】:

我有一个带有图像的结构数组。我需要将其保存到文件中以保持持久性。我可以将其转换为 Image 或 base64。

struct p: Identifiable, Hashable {
  var image: UIImage? = nil
  var name: String = ""
}

struct pD: Codable {
  var image: String = ""   //base64
  var name: String = ""
}

var pA = [p]
var pDA = [pD]

func convertImage2base64()

将 p 转换为 pD 的最便宜的方法是什么?我有带有图像和名称的 JSON 文件,我通过从 base64 图像和名称的 JSON 手动构建结构数组来导入。

到达 pD 的重点是让我可以立即进行 JSONdecode,而不是重建一个全新的临时结构数组。我觉得使用 map 进行数组转换可能会起作用,但我就是想不通。

我目前正在循环中使用 convertImage2base64() 复制数组的单个元素。这个过程似乎太昂贵了。

数据集不值得设置 Core Data。

【问题讨论】:

    标签: ios json swift image jsondecoder


    【解决方案1】:

    将图像存储为 Base64 在存储空间、内存和计算方面非常昂贵。我不推荐它,除非有特殊需要。如果您想要一个静态 JSON 文件,那么我建议将图像存储在单独的文件中(如 PNG 或 JPG 或任何它们),并在必要时将它们的 URL 存储在 JSON 中。如果您要存储的只是名称和图像,那么我会将它们放在一个目录中,并将名称作为文件名。那么文件系统就是你的数据库。在这种情况下不需要 JSON。如果需要,也可以在文件名中放入少量元数据。

    如果您想将所有内容存储在单个文件中,请查看二进制属性列表。他们可以直接存储Data,无需浪费地转换为Base64,并且直接支持Codeable。


    如果这也是您的服务器协议,而不仅仅是您描述的持久性模型,并且您更愿意将其作为 Base64 编码的 JSON 进行管理,而不是更高效的二进制协议,那么 Codable 可以直接处理它。

    extension P: Codable {
        enum CodingKeys: String, CodingKey {
            case image, name
        }
    
        func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(name, forKey: .name)
            try container.encodeIfPresent(image?.pngData()?.base64EncodedString(), forKey: .image)
        }
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            self.name = try container.decode(String.self, forKey: .name)
            let imageB64 = try container.decode(String.self, forKey: .image)
            if let imageData = Data(base64Encoded: imageB64) {
                self.image = UIImage(data: imageData)
            }
        }
    }
    

    以这种方式在本地对持久存储进行编码效率非常低,但正如您所说,iPhone 可以处理计算。但是,如果有很多小的更改(这会降低用户的闪存存储,它的写入次数是有限的),那么磁盘流失会很大,但它应该可以工作。

    【讨论】:

    • 有问题的 png 是一个简单的子 10k 文件。我的快速测试表明,iPhone 可以轻松处理 500 个这样的元素,基本上是一个带有微小人物图像的用户信息。我正在尝试在服务器周围来回发送这些数据,因此处理单个 json 比处理文件系统要友好得多。试图在编码/解码期间将所有内容都转换为字符串并处理类型转换。寻找廉价而优雅的方式在结构数组中的图像之间进行编码/解码。
    【解决方案2】:

    此解决方案使用 userdefault,对于大量数据,它不是一个好的选择。

    struct p: Codable {
        var imgData: Data
        var name: String
        
        public init(img: UIImage,name: String) {
            self.imgData = img.pngData()!
            self.name = name
        }
    }
    

    像这样使用 Userdefault Helper 来存储和获取数据:

    class UserDefaultsHandler: NSObject {
        static let shared = UserDefaultsHandler()
        let userDefaults: UserDefaults?
        
        private override init() {
            userDefaults = UserDefaults.standard
        }
        
        func set<T>(obj: T?, forKey key: String) where T: Encodable {
              guard let tempValue = obj else {
                  userDefaults?.set(nil, forKey: key)
                  return
              }
              let jsonEncoder = JSONEncoder()
              guard let jsonData = try? jsonEncoder.encode(tempValue) else {
                  userDefaults?.set(nil, forKey: key)
                  return
              }
              let json = String(data: jsonData, encoding: .utf8)
              userDefaults?.set(json, forKey: key)
          }
         
          func get<T: Decodable>(key: String, type: T.Type) -> T? {
              let jsonString = userDefaults?.object(forKey: key) as? String
              let jsonData = jsonString?.data(using: .utf8)
              let decoder = JSONDecoder()
              return try? decoder.decode(type, from: jsonData ?? Data())
          }
    }
    

    // 设置获取示例

      let arr = [p(img: img, name: "Apple"), p(img: img, name: "Mango"), p(img: img, name: "Pinapple")]
                    UserDefaultsHandler.shared.set(obj: arr, forKey: "ImageArray")
    
    
     guard let arr = UserDefaultsHandler.shared.get(key: "ImageArray", type: [p].self) else { return }
    

    【讨论】:

    • 我正在尝试对此进行解码。看起来您可以在数据位于 UserDefaults 时进行解码,因为它是关键数据的一部分,而不是 Foundation 类型。只需将 img 数据作为字符串抓取,无需任何转换。 *叹息..
    • 它保存在userdefault中,因为'p'符合'Encodable',因此使用该属性Data而不是UIImage。
    猜你喜欢
    • 2019-12-10
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 2016-05-22
    • 2017-04-03
    • 1970-01-01
    相关资源
    最近更新 更多