Swift 可编码循环
我有以下类型的课程:Swift 可编码循环,swift,codable,Swift,Codable,我有以下类型的课程: import UIKit class Report: Codable { var name: String = "" var budgetLines: [ReportLines] = [] init() { self.name = "My Report" self.budgetLines = [ReportLines(name: "Test1", parent: self), ReportLines(name: "
import UIKit
class Report: Codable {
var name: String = ""
var budgetLines: [ReportLines] = []
init() {
self.name = "My Report"
self.budgetLines = [ReportLines(name: "Test1", parent: self), ReportLines(name: "Test2", parent: self), ReportLines(name: "Test3", parent: self)]
}
}
class ReportLines: Codable {
var name: String
weak var parent: Report?
init(name: String, parent: Report) {
self.name = name
self.parent = parent
}
}
let report = Report()
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let archiveURL = documentsDirectory.appendingPathComponent("Report").appendingPathExtension("plist")
let propertyListEncoder = PropertyListEncoder()
let encodedReport = try? propertyListEncoder.encode(report)
try? encodedReport?.write(to: archiveURL, options: .noFileProtection)
重要详细信息:ReportLines
类包含指向所属报告的指针。我们的想法是可以编写如下代码:
myReportLine.parent!.name
当我试图将其保存到plist中时,编码操作挂起。我怀疑是这样的,因为它试图对一个对象进行编码,该对象包含一个包含指向外部对象指针的对象数组。Codable可能会进入一个循环
如何防止这种情况发生?我找到了以下解决方案:
import UIKit
class Report: Codable {
var name: String = ""
var reportLines: [ReportLine] = []
enum ReportCodingKeys: String, CodingKey {
case name
case reportLines
}
init() {
self.name = "My Report"
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: ReportCodingKeys.self)
name = try values.decode(String.self, forKey: .name)
reportLines = try values.decode([ReportLine].self, forKey: .reportLines)
for reportLine in reportLines {
reportLine.parent = self
}
}
func addReportLine(name: String) {
reportLines.append(ReportLine(name: name, parent: self))
}
}
class ReportLine: Codable {
var name: String
weak var parent: Report?
enum CodingKeys: String, CodingKey {
case name
}
init(name: String, parent: Report) {
self.name = name
self.parent = parent
}
}
let report = Report()
report.addReportLine(name: "Test1")
report.addReportLine(name: "Test2")
report.addReportLine(name: "Test3")
// Saving
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let archiveURL = documentsDirectory.appendingPathComponent("Report").appendingPathExtension("plist")
let propertyListEncoder = PropertyListEncoder()
var encodedReport = try? propertyListEncoder.encode(report)
try? encodedReport?.write(to: archiveURL, options: .noFileProtection)
// Retrieving
let propertyListDecoder = PropertyListDecoder()
encodedReport = try? Data(contentsOf: archiveURL)
let report2 = try? propertyListDecoder.decode(Report.self, from: encodedReport!)
// Comparing
print("\(report.reportLines[2].name ?? "nil")")
print("report!.reportLines[0].parent: \(String(describing: report.reportLines[2].parent?.name ?? "nil"))")
print("\(report2?.reportLines[2].name ?? "nil")")
print("report2!.reportLines[0].parent: \(String(describing: report2?.reportLines[2].parent?.name ?? "nil"))")
我唯一问自己的是:有没有更好的方法来调用默认解码器,而不是自己提供init(from:)
希望这有帮助。好主意!您还可以通过执行reportLines.forEach(){$0.parent=self}
来缩短它,因为您有一个循环依赖项(parent)——这就是它导致循环的原因。只有手动可编码实现才能解决这个问题。