当前位置: 首页 > 知识库问答 >
问题:

Swift 5:将复杂对象保存到文件存储

薛扬
2023-03-14

我正在完成一项学校作业,为此我必须在Swift5中开发一个iOS应用程序。应用程序需要利用web服务(web-API)和文件存储或用户默认值。

我选择开发一个“QR code Manager”,用户可以通过设置一些设计参数为URL创建QR代码,然后将这些参数发送到生成器API。这个API(在OK请求时)返回一个指定格式的图像(在我的例子中是PNG)。

我有一个类与URL和所有设计属性的二维码,其中也将包含图像本身。请参阅下面的类代码片段。

public class QRCode {
    
    var bsId : Int?
    var url : String?
    var name: String?
    var frame: Frame?
    var logo: QrCodeLogo?
    var marker: Marker?
    var color : String?
    var bgColor : String?
    var image : Data?
    
    
    init(data: [String:String]) {
        self.url = data["url"]
        self.frame = Frame.allCases.first(where: { $0.description == data["frame"] })
        self.logo = QrCodeLogo.allCases.first(where: { $0.description == data["logo"] })
        self.marker = Marker.allCases.first(where: { $0.description == data["marker"] })
        self.bgColor = data["backGroundColor"]
        self.color = data["colorLight"]
    }
    
    init(json: String) {
        // todo
    }
}

extension QRCode {
    func toDict() -> [String:Any] {
        var dict = [String:Any]();
        let otherSelf = Mirror(reflecting: self);
        for child in otherSelf.children {
            if let key = child.label {
                dict[key] = child.value;
            }
        }
        return dict;
    }
}

为了便于开发,所有的属性都是空的,一旦我成功地实现了所有的东西,类将被进一步重构。

我尝试了我在网上找到的各种方法,其中一种可以在类扩展中找到。函数todict()将对象属性及其值转换为[string:any]类型的Dictionary对象。但是,我读到当对any数据类型进行编码然后进行解码时,Swift无法确定解码的数据应该是哪种复杂的数据类型,从而有效地使数据变得没有意义或不可用。

我发现的另一种方法是通过扩展类中的codable-协议。然而,据我所知,codable只接受基本数据类型。

请在下面找到我当前编写的文件存储处理代码。虽然还没有完成,但我觉得这是一个很好的开始,可能会对这个问题有所帮助。


class StorageManager {
    
    fileprivate let filemanager: FileManager = FileManager.default;
    
    fileprivate func filePath(forKey key: String) -> URL? {
        guard let docURL = filemanager.urls(for: .documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first else {
            return nil;
        }
        
        return docURL.appendingPathComponent(key);
    }
    
    func writeToStorage(identifier: String, data: QRCode) -> Void {
        guard let path = filePath(forKey: identifier) else {
            throw ApplicationErrors.runtimeError("Something went wrong writing the file to storage");
        }
        
        let dict = data.toDict();
        // TODO:: Implement
    }
    
    func readFromStorage(identifier: String) -> Any {
        // TODO:: Implement
        return 0;
    }
    
    func readAllFromStorage() throws -> [URL] {
        let docsURL = filemanager.urls(for: .documentDirectory, in: .userDomainMask)[0];
        
        do {
            let fileURLs = try filemanager.contentsOfDirectory(at: docsURL, includingPropertiesForKeys: nil);
            
            return fileURLs;
        } catch {
            throw ApplicationErrors.runtimeError("Something went wrong retrieving the files from \(docsURL.path): \(error.localizedDescription)");
        }
    }
}

我对Swift还是个新手,我的文件存储卡在了我的头上。有没有什么方法可以将该类的实例存储在文件存储中,以便在检索数据时重新n实例化该类?

提前谢谢!如果有任何问题,请不要犹豫。

基于Matt的评论,请在下面找到markerframeQRCodeLogo枚举的代码片段。框架枚举:


public enum Frame: String, CaseIterable {
    case noFrame
    case bottomFrame
    case bottomTooltip
    case topHeader
    static var count: Int { return 4 }
    
    var description: String {
        switch self {
        case .noFrame:
            return "no-frame"
        case .bottomFrame:
            return "bottom-frame"
        case .bottomTooltip:
            return "bottom-tooltip"
        case .topHeader:
            return "top-header"
        }
    }
}

QRCodeLogo枚举:

public enum QrCodeLogo: String, CaseIterable {
    case noLogo
    case scanMe
    case scanMeSquare
    static var count: Int { return 3 }
    
    var description: String {
        switch self {
        case .noLogo:
            return "no-logo"
        case .scanMe:
            return "scan-me"
        case .scanMeSquare:
            return "scan-me-square"
        }
    }
}

标记枚举:

public enum Marker: String, CaseIterable {
    case version1
    case version2
    case version3
    case version4
    case version5
    case version6
    case version7
    case version8
    case version9
    case version10
    case version11
    case version12
    case version13
    case version15
    case version16
    static var count: Int { return 15 }
    
    var description: String {
        switch self {
        case .version1:
            return "version1"
        case .version2:
            return "version2"
        case .version3:
            return "version3"
        case .version4:
            return "version4"
        case .version5:
            return "version5"
        case .version6:
            return "version6"
        case .version7:
            return "version7"
        case .version8:
            return "version8"
        case .version9:
            return "version9"
        case .version10:
            return "version10"
        case .version11:
            return "version11"
        case .version12:
            return "version12"
        case .version13:
            return "version13"
        case .version15:
            return "version15"
        case .version16:
            return "version16"
        }
    }
}

上述所有枚举都包含我所使用的API的有效设计选项。它们用作输入限制,以防止出现“无效参数”错误。

希望这能把事情搞清楚。

再次感谢!

共有1个答案

能逸清
2023-03-14

一个类型可以符合Codable,前提是它的所有属性都符合Codable。除了枚举之外,您的所有属性都符合Codable,如果您声明它们符合Codable,那么它们也将符合Codable。因此,您的类型的这个简单草图将编译:

public enum Frame: String, Codable {
    case noFrame
    case bottomFrame
    case bottomTooltip
    case topHeader
}
public enum QrCodeLogo: String, Codable {
    case noLogo
    case scanMe
    case scanMeSquare
}
public enum Marker: String, Codable {
    case version1
    case version2
    case version3
    case version4
    case version5
    case version6
    case version7
    case version8
    case version9
    case version10
    case version11
    case version12
    case version13
    case version15
    case version16
}
public class QRCode : Codable {
    var bsId : Int?
    var url : String?
    var name: String?
    var frame: Frame?
    var logo: QrCodeLogo?
    var marker: Marker?
    var color : String?
    var bgColor : String?
    var image : Data?
}

关于您的代码,还有很多很多其他的地方可以改进。您不需要对任何事情使用CaseIterable或description。现在您的类型是可编码的,您可以使用它直接自动地从JSON检索值。如果您的枚举事例的名称与相应的JSON键不匹配,只需制作一个CodingKey嵌套枚举来充当桥接器。

换句话说,可编码使得您的类型既可以直接从JSON填充,也可以序列化到磁盘。

 类似资料:
  • 问题内容: 我想将一个对象保存到文件中,然后轻松地从文件中读取它。作为一个简单的示例,可以说我有以下3d数组: 是否有一个简单的Ruby API,无需编程解析器即可解释文件中的数据,就可以用来实现此目的?在示例中,我给出了一个简单的例子,但是随着对象变得越来越复杂,使对象持久化变得很烦人。 问题答案: 参见元帅:http : //ruby- doc.org/core/classes/Marshal

  • 问题内容: 我看到过很多不同的文章,涉及到您应该以何种方式将对象序列化到文件,并且所有这些在本质上在执行方式和最佳实践方面存在冲突。因此,这就是我要保存的内容: 我们可以假设configArgs的大小已知,我需要制作一个文件,这就是到目前为止的内容。 问题答案: 好吧,我想,您想将对象直接写入文件 我只是提供了重要的代码。通过异常处理来实现。

  • 问题内容: 我目前利用以下内容将文件上传到S3: 上面的方法工作正常,但我想直接将a保存到S3以从应用程序中删除几秒钟,但是我不知道如何执行此操作?这是我当前将图像保存到文件中的方式: 有没有一种方法可以直接以流的形式直接写入Amazon S3,如果可以,有人可以显示示例吗? 另外,这是个好主意吗?如果它容易出错,我将继续使用当前方法。任何建议表示赞赏。 问题答案: 以下(或类似的东西)应该可以正

  • 问题内容: 我已经创建了一个JSON文件,并且需要能够通过电子邮件与其他协作者共享该文件。但是,尽管在R工作区中有许多处理JSON对象的主题,但实际上没有资源讨论如何实际将JSON对象导出到.JSON文件。 这是一个简单的例子: 最后一行,尝试读取JSON文件,导致错误:“ fromJSON(file =“ export.JSON”)中的错误:意外字符’R’” 显然,save()函数并不是可行的方

  • 问题内容: 我正在尝试使用适用于AWS的新boto3客户端做一个“ hello world” 。 我的用例非常简单:从S3获取对象并将其保存到文件中。 在boto 2.XI中,它应该是这样的: 在boto 3中。我找不到一种干净的方法来做同样的事情,所以我手动遍历了“ Streaming”对象: 要么 而且效果很好。我想知道是否有任何“本机” boto3函数可以完成相同的任务? 问题答案: Bot

  • 我正在尝试为AWS的新boto3客户端做一个“hello world”。 我的用例相当简单:从S3获取对象并将其保存到文件中。 在boto 2.X中,我会这样做: 在博托3。我找不到一种干净的方法来做同样的事情,所以我手动迭代“流”对象: 或 而且效果很好。我想知道是否有任何“本机”boto3函数可以完成相同的任务?

  • 我尝试用以下代码保存从internet下载的文件 但在运行时,我得到的错误如下 03-04 20:42:51.080 8972-8972/com.example.me.demo2 E/BitmapFactory:无法解码流:java.io.FileNotFoundExcoop: /storage/emulated/0/.tanks/4a100abb-0e55-4062-8c37-f11f4189e

  • 本文向大家介绍Java将对象保存到文件中/从文件中读取对象的方法,包括了Java将对象保存到文件中/从文件中读取对象的方法的使用技巧和注意事项,需要的朋友参考一下 1.保存对象到文件中 Java语言只能将实现了Serializable接口的类的对象保存到文件中,利用如下方法即可: 参数obj一定要实现Serializable接口,否则会抛出java.io.NotSerializableExcept