After writing that last post , I fell into the trap that
I was afraid I would: I spent my free coding time this week working on a
persistence scheme instead of on feature work on my app.
But I’m moderately happy with what I’ve come up with. As planned, it uses a weak
cache in front of CouchBaseLite . CBL is a document data store. It stores
indexed JSON, which we turn into Swift objects through Gloss -inspired
encoding and decoding.
The whole thing is under 100 lines of code so far, and a lot of that is
exception handling, so I think the ideas are pretty straightforward. It could
probably use a large helping of syntactic sugar and some thought put into
reference cycles and patterns for searching, but it’s a start…
I’ve cheekily nicknamed it dali , after Salvador Dalí, in honor of
The Persistence of Memory .
Here’s what some familiar sample objects look like:
class Shape : Persistable {
class var kind : String { return "Shape" }
let identifier = NSUUID () . UUIDString
var area : Double {
return 0.0
}
init () { }
required init ?( with json : JSON , from persistence : Persistence ) throws { }
func save ( to : Persistence ) throws {
try to . save ( self , json : [:])
}
}
class Square : Shape {
override class var kind : String { return "Square" }
let side : Double
override var area : Double {
return side * side
}
init ( side : Double ) {
self . side = side
super . init ()
}
required init ?( with json : JSON , from persistence : Persistence ) throws {
guard let side : Double = "side" <~~ json else { return nil }
self . side = side
try super . init ( with : json , from : persistence )
}
override func save ( to : Persistence ) throws {
try to . save ( self , json : [ "side" : side ])
}
}
class Circle : Shape {
override class var kind : String { return "Circle" }
let radius : Double
override var area : Double {
return M_PI * radius * radius
}
init ( radius : Double ) {
self . radius = radius
super . init ()
}
required init ?( with json : JSON , from persistence : Persistence ) throws {
guard let radius : Double = "radius" <~~ json else { return nil }
self . radius = radius
try super . init ( with : json , from : persistence )
}
override func save ( to : Persistence ) throws {
try to . save ( self , json : [ "radius" : radius ])
}
}
Relationships are simply stored identifiers.
final class VennDiagram : Persistable {
static let kind = "VennDiagram"
let identifier = NSUUID () . UUIDString
let left : Circle
let right : Circle
init ( left : Circle , right : Circle ) {
self . left = left
self . right = right
}
required init ?( with json : JSON , from persistence : Persistence ) throws {
guard let left : Circle = try persistence . load ( "left" <~~ json ),
right : Circle = try persistence . load ( "right" <~~ json )
else { return nil }
self . left = left
self . right = right
}
func save ( to : Persistence ) throws {
try left . save ( to )
try right . save ( to )
try to . save ( self , json : [ "left" : left . identifier , "right" : right . identifier ])
}
}
They can be lazily instantiated if desired.
final class LazySquare : Persistable {
static let kind = "LazySquare"
let identifier = NSUUID () . UUIDString
private weak var persistence : Persistence ?
private var squareIdentifier : String ?
lazy var square : Square ? = try! self . persistence ? . load ( self . squareIdentifier )
init ( square : Square ) {
self . square = square
}
required init ?( with json : JSON , from persistence : Persistence ) throws {
self . persistence = persistence
self . squareIdentifier = "square" <~~ json
}
func save ( to : Persistence ) throws {
if let square = square {
try square . save ( to )
try to . save ( self , json : [ "square" : square . identifier ])
} else {
try to . save ( self , json : [:])
}
}
}