如何解决Swift 5:将复杂对象保存到文件存储
我正在处理学校作业,必须在Swift 5中开发一个iOS应用程序。该应用程序需要利用Web服务(Web API)以及文件存储或用户默认设置。
我选择开发“ QR代码管理器”,用户可以通过设置一些设计参数来为URL创建QR代码,然后将其发送到生成器API。此API(根据“确定”请求)以指定的格式(以我的情况为PNG)返回图像。
我有一个包含URL和QR码所有设计属性的类,其中还将包含图像本身。请参见下面的代码段。
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()
将对象属性及其值转换为类型Dictionary
的{{1}}对象。但是,我读到[String:Any]
数据类型经过编码然后解码时,Swift无法确定解码后的数据应该是哪种复杂数据类型,从而使数据变得毫无意义或无法使用。
我发现的另一种方法是通过扩展类中的Any
协议。据我所知,Codable
仅接受原始数据类型。
请在下面找到我当前编写的用于文件存储处理的代码。尚未完成,但是我觉得这是一个不错的开始,可能会在这个问题上有所帮助。
Codable
我对Swift还是很陌生,并且我卡在文件存储上。有什么方法可以将此类的实例存储在文件存储中,以便在检索数据时可以重新实例化此类?
提前谢谢!如果有任何疑问,请不要犹豫。
编辑
根据马特的评论,请在下面找到
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)");
}
}
}
,Marker
和Frame
枚举的代码段。
QrCodelogo
枚举:
Frame
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"
}
}
}
枚举:
Marker
以上所有枚举都包含我使用的API的有效设计选项。它们用作输入限制,以防止发生“无效参数”错误。
希望这可以清除一切。
再次感谢!
解决方法
只要类型的所有属性都符合Codable,则该类型可以符合Codable。您的所有属性 do 都符合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
。现在您的类型是可编码的,您可以使用 it 直接从JSON直接自动检索值。如果您的枚举案例的名称与相应的JSON键不匹配,则只需制作一个CodingKey嵌套枚举即可充当桥梁。
换句话说,可编码使得您的类型两者都可以直接从JSON 填充,并且可以序列化到磁盘。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。