Swift Portable Object Notation (SPON)
For iOS, tvOS and macOS development with Swift and XcodeAvailable exclusively as part of the Action Data framework.
Swift Portable Object Notation
The new Swift Portable Object Notation (SPON) data format that allows complex data models to be encoded in a portable text string that encodes not only property keys and data, but also includes type information about the encoded data.
The portable, human-readable string format encodes values with a single character type designator as follows:
%
– Bool!
– Int$
– String^
– Float&
– Double*
– EmbeddedNSData
orData
value
Additionally, embedded arrays will be in the @array[...]
format and embedded dictionaries in the @obj:type<...>
format.
Take the following sample objects:
import Foundation
import ActionUtilities
import ActionData
struct Address: Codable {
var addr1 = ""
var addr2 = ""
var city = ""
var state = ""
var zip = ""
}
class Person: ADDataTable {
static var tableName = "People"
static var primaryKey = "id"
static var primaryKeyType = ADDataTableKeyType.autoUUIDString
var id = UUID().uuidString
var firstName = ""
var lastName = ""
var addresses: [String:Address] = [:]
required init() {
}
init(firstName: String, lastName:String, addresses: [String:Address] = [:]) {
self.firstName = firstName
self.lastName = lastName
self.addresses = addresses
}
}
class Group: ADDataTable {
static var tableName = "Groups"
static var primaryKey = "id"
static var primaryKeyType = ADDataTableKeyType.autoUUIDString
var id = UUID().uuidString
var name = ""
var people = ADCrossReference<Person>(name: "PeopleInGroup", leftKeyName: "groupID", rightKeyName: "personID")
required init() {
}
init(name: String, people: [Person] = []) {
self.name = name
self.people.storage = people
}
}
A populated Address
struct above could be represented in SPON as:
@obj:Address<state$=`TX` city$=`Seabrook` addr1$=`25 Nasa Rd 1` zip$=`77586` addr2$=`Apt #123`>
ADSPONEncoder
Encodes a Codable
or Encodable
class into a ADRecord
that can be written into a SQLite database using a ADSPONiteProvider
. The result is a dictionary of key/value pairs representing the data currently stored in the class. This encoder will automatically handle URLs
and Enums
(if the Enum is value based and also marked Codable
or Encodable
).
Example:
import ActionUtilities
import ActionData
class Category: ADDataTable {
enum CategoryType: String, Codable {
case local
case web
}
static var tableName = "Categories"
static var primaryKey = "id"
static var primaryKeyType: ADDataTableKeyType = .computedInt
var id = 0
var added = Date()
var name = ""
var description = ""
var enabled = true
var highlightColor = UIColor.white.toHex()
var type: CategoryType = .local
var icon: Data = UIImage().toData()
required init() {
}
}
let encoder = ADSPONEncoder()
let category = Category()
let data = try encoder.encode(category)
Remark:
To store UIColors
in the record use the toHex()
extension method and to store UIImages
use the toData()
extension method.
ADSPONDecoder
Decodes a Codable
or Decodable
class from a ADRecord
read from a SQLite database using a ADSPONiteProvider
. The result is an instance of the class with the properties set from the database record. This decoder will automatically handle URLs
and Enums
(if the Enum is value based and also marked Codable
or Decodable
).
Example:
import ActionUtilities
import ActionData
class Category: ADDataTable {
enum CategoryType: String, Codable {
case local
case web
}
static var tableName = "Categories"
static var primaryKey = "id"
static var primaryKeyType: ADDataTableKeyType = .computedInt
var id = 0
var added = Date()
var name = ""
var description = ""
var enabled = true
var highlightColor = UIColor.white.toHex()
var type: CategoryType = .local
var icon: Data = UIImage().toData()
required init() {
}
}
let encoder = ADSPONEncoder()
let category = Category()
let data = try encoder.encode(category)
let decoder = ADSPONDecoder()
let category2 = try decoder.decode(Category.self, from: data)
Remark:
To retrieve UIColors
in the record use the String.uiColor
extension property and to retrieve UIImages
use the String.uiImage
extension property.
ADSPONProvider
The ADSPONProvider
provides both light-weight, low-level access to data stored in a Swift Portable Object Notation (SPON) database and high-level access via a Object Relationship Management (ORM) model. Use provided functions to read and write data stored in a ADRecord
format from and to the database using SQL statements directly.
Example:
let provider = ADSPONProvider.shared
let record = try provider.query("SELECT * FROM Categories WHERE id = ?", withParameters: [1])
print(record["name"])
Optionally, pass a class instance conforming to the ADDataTable
protocol to the ADSPONProvider
and it will automatically handle reading, writing and deleting data as required.
Example:
let addr1 = Address(addr1: "PO Box 1234", addr2: "", city: "Houston", state: "TX", zip: "77012")
let addr2 = Address(addr1: "25 Nasa Rd 1", addr2: "Apt #123", city: "Seabrook", state: "TX", zip: "77586")
let p1 = Person(firstName: "John", lastName: "Doe", addresses: ["home":addr1, "work":addr2])
let p2 = Person(firstName: "Sue", lastName: "Smith", addresses: ["home":addr1, "work":addr2])
let group = Group(name: "Employees", people: [p1, p2])
try provider.save(group)
Remark:
The ADSPONProvider
will automatically create a SQL Table from a class instance if one does not already exist. In addition, ADSPONProvider
contains routines to preregister or update the schema classes conforming to the ADDataTable
protocol which will build or modify the database tables as required.