我有一个自定义模型,其中包含多个类,这些类是我在Swift中为基于文档的Mac应用程序编写的。当用户向其文档输入数据时,将创建一个类Itinerary
的实例并将其存储在一个数组中,该数组是另一个类Course
的另一个“根”对象的属性。最重要的是,可以创建多个课程,并将它们存储在应用程序的Document类的数组中。我希望用户能够保存他们的数据并在以后重新加载它。所以我试图在我的自定义类型上实现Codable协议。
可编码的一致性很好;当我尝试保存时,将生成所需的JSON文件。问题出在解码时。
在尝试对每个路线进行解码时,需要在初始化结束之前设置其course
属性,因为它被定义为指向其所属路线的无主var。发生这种情况的地方位于课程的addItinerary(_:)
函数中,该函数直接在行程的指定初始值设定项中调用。这意味着我还需要将课程传递给行程的指定init。这就是问题所在……当我尝试从可解码的初始值设定项中重新初始化行程时,我无权访问需要添加行程的过程,因此无法在设置过程中设置course
属性初始化。
问题似乎围绕着我如何尝试初始化路线以及我如何尝试管理内存。一项研究表明,我的方向是将课程属性更改为可选的弱变量(即weak var course: Course?
或将其标记为隐式未包装的可选变量,即var course: Course!
)。这两个选项似乎都可能在模型中引入了不必要的复杂性,因为我将需要重写行程初始化器。根据Apple的文档,将某个属性标记为无主when the other instance has the same lifetime or a longer lifetime是适当的,这可以在此处准确地描述这种情况。
我的问题有两个方面。尝试初始化模型似乎存在一个固有缺陷:
为了简洁起见,我从似乎无关的类中排除了所有属性。但是,如果人们认为有必要提供完整的解决方案,我将提供更多代码。
注意事项的简明注释:
course
属性进行编码的情况下产生的。addItinerary(_:)
函数是在设置了行程的course
属性时……在行程的指定init中调用。但是...在解码时无法调用该init,因为我从未对课程进行编码...当我尝试在行程的encode(to:)
中对课程进行编码时,Xcode会抛出BAD ACCESS错误,并且指向我不确定如何调试的内存中的地址。
class Document: NSDocument {
var masterCourseList = [Course]()
}
class Course: NSObject {
// ...other properties
private(set) var itineraries: [Itinerary]() {
didSet {
// sorting code
}
}
func addItinerary(_ itinerary: Itinerary) {
itinerary.course = self
self.itineraries.append(itinerary)
}
// encodable conformance
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
// ...encode other properties
try container.encode(itineraries, forKey: .itineraries)
}
// decodable conformance
required convenience init decode(from: Decoder) throws {
let decoder = try decoder.container(keyedBy: CodingKeys.self)
// ...decode other properties
let decodedItineraries = container.decode(Array<Itinerary>.self, forKey: .itineraries)
self.init()
for itinerary in decodedItineraries {
self.addItinerary(itinerary)
}
}
enum CodingKeys: CodingKey {
case itineraries, // other keys... //
}
}
class Itinerary: NSObject {
@objc dynamic let date: Date
unowned var course: Course
// ...other properties
private init(date: Date, course: Course) {
self.course = course
self.date = date
super.init()
course.addItinerary(self)
}
// encodable conformance
func encode(to encoder: Encoder) throws {
// ...encode all the desired properties of itinerary class
// ...never encoded the 'course' property but still got the desired JSON file
}
// decodable conformance
required convenience init(from decoder: Decoder) throws {
// ...decode all the properties
// ...never decoded the 'course' property because it was never encoded
self.init(date: decodedDate, course: decodedCourse)
}
}
还有正在生成的JSON示例...
[
{
"itineraries" : [
{
"date" : 587357150.51135898
},
{
"date" : 587443563.588081
}
],
"title" : "sample course 1",
"startDate" : 587357146.98558402,
"endDate" : 587789146.98558402
},
{
"itineraries" : [
{
"date" : 587357150.51135898
},
{
"date" : 587443563.588081
},
{
"date" : 587443563.588081
}
],
"title" : "sample course 2",
"startDate" : 587957146.98558402,
"endDate" : 588389146.98558402
}
]