converted the Demo app's observer demo to use CoreStoreObject instead of NSManagedObject

This commit is contained in:
John Estropia
2017-06-14 17:39:57 +09:00
parent 801cf8d9f0
commit e26573c18e
4 changed files with 107 additions and 104 deletions

View File

@@ -1,36 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="10169.1" systemVersion="15D21" minimumToolsVersion="Automatic"> <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="12141" systemVersion="16F73" minimumToolsVersion="Xcode 7.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
<entity name="Palette" representedClassName="CoreStoreDemo.Palette">
<attribute name="brightness" optional="YES" attributeType="Float" defaultValueString="0.0" syncable="YES"/>
<attribute name="colorName" optional="YES" transient="YES" attributeType="String" syncable="YES"/>
<attribute name="hue" optional="YES" attributeType="Integer 32" defaultValueString="0.0" syncable="YES"/>
<attribute name="saturation" optional="YES" attributeType="Float" defaultValueString="0.0" syncable="YES"/>
<userInfo/>
</entity>
<entity name="Place" representedClassName="CoreStoreDemo.Place" syncable="YES"> <entity name="Place" representedClassName="CoreStoreDemo.Place" syncable="YES">
<attribute name="latitude" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/> <attribute name="latitude" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="longitude" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/> <attribute name="longitude" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="subtitle" optional="YES" attributeType="String" syncable="YES"/> <attribute name="subtitle" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/> <attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
</entity> </entity>
<entity name="TimeZone" representedClassName="CoreStoreDemo.TimeZone" syncable="YES"> <entity name="TimeZone" representedClassName="CoreStoreDemo.TimeZone" syncable="YES">
<attribute name="abbreviation" optional="YES" attributeType="String" syncable="YES"/> <attribute name="abbreviation" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="daylightSavingTimeOffset" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/> <attribute name="daylightSavingTimeOffset" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasDaylightSavingTime" optional="YES" attributeType="Boolean" syncable="YES"/> <attribute name="hasDaylightSavingTime" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/> <attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="secondsFromGMT" optional="YES" attributeType="Integer 32" defaultValueString="0.0" syncable="YES"/> <attribute name="secondsFromGMT" optional="YES" attributeType="Integer 32" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
</entity> </entity>
<configuration name="FetchingAndQueryingDemo"> <configuration name="FetchingAndQueryingDemo">
<memberEntity name="TimeZone"/> <memberEntity name="TimeZone"/>
</configuration> </configuration>
<configuration name="ObservingDemo">
<memberEntity name="Palette"/>
</configuration>
<configuration name="TransactionsDemo"> <configuration name="TransactionsDemo">
<memberEntity name="Place"/> <memberEntity name="Place"/>
</configuration> </configuration>
<elements> <elements>
<element name="Palette" positionX="261" positionY="189" width="128" height="105"/>
<element name="Place" positionX="261" positionY="225" width="128" height="105"/> <element name="Place" positionX="261" positionY="225" width="128" height="105"/>
<element name="TimeZone" positionX="297" positionY="270" width="128" height="120"/> <element name="TimeZone" positionX="297" positionY="270" width="128" height="120"/>
</elements> </elements>

View File

@@ -10,7 +10,7 @@ import UIKit
import CoreStore import CoreStore
private struct Static { struct ColorsDemo {
enum Filter: String { enum Filter: String {
@@ -33,8 +33,8 @@ private struct Static {
switch self { switch self {
case .all: return Where(true) case .all: return Where(true)
case .light: return Where("%K >= %@", #keyPath(Palette.brightness), 0.9) case .light: return Palette.where({ $0.brightness >= 0.9 })
case .dark: return Where("%K <= %@", #keyPath(Palette.brightness), 0.4) case .dark: return Palette.where({ $0.brightness <= 0.4 })
} }
} }
} }
@@ -45,25 +45,38 @@ private struct Static {
self.palettes.refetch( self.palettes.refetch(
self.filter.whereClause(), self.filter.whereClause(),
OrderBy(.ascending(#keyPath(Palette.hue))) Palette.orderBy(ascending: { $0.hue })
) )
} }
} }
static let stack: DataStack = {
return DataStack(
CoreStoreSchema(
modelVersion: "ColorsDemo",
entities: [
Entity<Palette>("Palette"),
],
versionLock: [
"Palette": [0x8c25aa53c7c90a28, 0xa243a34d25f1a3a7, 0x56565b6935b6055a, 0x4f988bb257bf274f]
]
)
)
}()
static let palettes: ListMonitor<Palette> = { static let palettes: ListMonitor<Palette> = {
try! CoreStore.addStorageAndWait( try! ColorsDemo.stack.addStorageAndWait(
SQLiteStore( SQLiteStore(
fileName: "ColorsDemo.sqlite", fileName: "ColorsDemo.sqlite",
configuration: "ObservingDemo",
localStorageOptions: .recreateStoreOnModelMismatch localStorageOptions: .recreateStoreOnModelMismatch
) )
) )
return ColorsDemo.stack.monitorSectionedList(
return CoreStore.monitorSectionedList(
From<Palette>(), From<Palette>(),
SectionBy(#keyPath(Palette.colorName)), SectionBy(Palette.keyPath({ $0.colorName })),
OrderBy(.ascending(#keyPath(Palette.hue))) Palette.orderBy(ascending: { $0.hue })
) )
}() }()
} }
@@ -77,7 +90,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
deinit { deinit {
Static.palettes.removeObserver(self) ColorsDemo.palettes.removeObserver(self)
} }
@@ -98,7 +111,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
] ]
let filterBarButton = UIBarButtonItem( let filterBarButton = UIBarButtonItem(
title: Static.filter.rawValue, title: ColorsDemo.filter.rawValue,
style: .plain, style: .plain,
target: self, target: self,
action: #selector(self.filterBarButtonItemTouched(_:)) action: #selector(self.filterBarButtonItemTouched(_:))
@@ -113,9 +126,9 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
] ]
self.filterBarButton = filterBarButton self.filterBarButton = filterBarButton
Static.palettes.addObserver(self) ColorsDemo.palettes.addObserver(self)
self.setTable(enabled: !Static.palettes.isPendingRefetch) self.setTable(enabled: !ColorsDemo.palettes.isPendingRefetch)
} }
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
@@ -137,19 +150,19 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
override func numberOfSections(in tableView: UITableView) -> Int { override func numberOfSections(in tableView: UITableView) -> Int {
return Static.palettes.numberOfSections() return ColorsDemo.palettes.numberOfSections()
} }
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Static.palettes.numberOfObjectsInSection(section) return ColorsDemo.palettes.numberOfObjectsInSection(section)
} }
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PaletteTableViewCell") as! PaletteTableViewCell let cell = tableView.dequeueReusableCell(withIdentifier: "PaletteTableViewCell") as! PaletteTableViewCell
let palette = Static.palettes[indexPath] let palette = ColorsDemo.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color cell.colorView?.backgroundColor = palette.color
cell.label?.text = palette.colorText cell.label?.text = palette.colorText
@@ -165,7 +178,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
self.performSegue( self.performSegue(
withIdentifier: "ObjectObserverDemoViewController", withIdentifier: "ObjectObserverDemoViewController",
sender: Static.palettes[indexPath] sender: ColorsDemo.palettes[indexPath]
) )
} }
@@ -174,8 +187,8 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
switch editingStyle { switch editingStyle {
case .delete: case .delete:
let palette = Static.palettes[indexPath] let palette = ColorsDemo.palettes[indexPath]
CoreStore.perform( ColorsDemo.stack.perform(
asynchronous: { (transaction) in asynchronous: { (transaction) in
transaction.delete(palette) transaction.delete(palette)
@@ -190,7 +203,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return Static.palettes.sectionInfoAtIndex(section).name return ColorsDemo.palettes.sectionInfoAtIndex(section).name
} }
@@ -213,7 +226,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
func listMonitorDidRefetch(_ monitor: ListMonitor<Palette>) { func listMonitorDidRefetch(_ monitor: ListMonitor<Palette>) {
self.filterBarButton?.title = Static.filter.rawValue self.filterBarButton?.title = ColorsDemo.filter.rawValue
self.tableView.reloadData() self.tableView.reloadData()
self.setTable(enabled: true) self.setTable(enabled: true)
} }
@@ -235,7 +248,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
if let cell = self.tableView.cellForRow(at: indexPath) as? PaletteTableViewCell { if let cell = self.tableView.cellForRow(at: indexPath) as? PaletteTableViewCell {
let palette = Static.palettes[indexPath] let palette = ColorsDemo.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color cell.colorView?.backgroundColor = palette.color
cell.label?.text = palette.colorText cell.label?.text = palette.colorText
} }
@@ -268,7 +281,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
@IBAction private dynamic func resetBarButtonItemTouched(_ sender: AnyObject?) { @IBAction private dynamic func resetBarButtonItemTouched(_ sender: AnyObject?) {
CoreStore.perform( ColorsDemo.stack.perform(
asynchronous: { (transaction) in asynchronous: { (transaction) in
transaction.deleteAll(From<Palette>()) transaction.deleteAll(From<Palette>())
@@ -279,16 +292,16 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
@IBAction private dynamic func filterBarButtonItemTouched(_ sender: AnyObject?) { @IBAction private dynamic func filterBarButtonItemTouched(_ sender: AnyObject?) {
Static.filter = Static.filter.next() ColorsDemo.filter = ColorsDemo.filter.next()
} }
@IBAction private dynamic func addBarButtonItemTouched(_ sender: AnyObject?) { @IBAction private dynamic func addBarButtonItemTouched(_ sender: AnyObject?) {
CoreStore.perform( ColorsDemo.stack.perform(
asynchronous: { (transaction) in asynchronous: { (transaction) in
let palette = transaction.create(Into<Palette>()) let palette = transaction.create(Into<Palette>())
palette.setInitialValues() palette.setInitialValues(in: transaction)
}, },
completion: { _ in } completion: { _ in }
) )

View File

@@ -29,7 +29,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
if let palette = newValue { if let palette = newValue {
self.monitor = CoreStore.monitorObject(palette) self.monitor = ColorsDemo.stack.monitorObject(palette)
} }
else { else {
@@ -50,22 +50,22 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
if let palette = CoreStore.fetchOne(From<Palette>(), OrderBy(.ascending(#keyPath(Palette.hue)))) { if let palette = ColorsDemo.stack.fetchOne(From<Palette>(), Palette.orderBy(ascending: { $0.hue })) {
self.monitor = CoreStore.monitorObject(palette) self.monitor = ColorsDemo.stack.monitorObject(palette)
} }
else { else {
_ = try? CoreStore.perform( _ = try? ColorsDemo.stack.perform(
synchronous: { (transaction) in synchronous: { (transaction) in
let palette = transaction.create(Into(Palette.self)) let palette = transaction.create(Into<Palette>())
palette.setInitialValues() palette.setInitialValues(in: transaction)
} }
) )
let palette = CoreStore.fetchOne(From<Palette>(), OrderBy(.ascending(#keyPath(Palette.hue))))! let palette = ColorsDemo.stack.fetchOne(From<Palette>(), Palette.orderBy(ascending: { $0.hue }))!
self.monitor = CoreStore.monitorObject(palette) self.monitor = ColorsDemo.stack.monitorObject(palette)
} }
super.init(coder: aDecoder) super.init(coder: aDecoder)
@@ -121,12 +121,12 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
@IBAction dynamic func hueSliderValueDidChange(_ sender: AnyObject?) { @IBAction dynamic func hueSliderValueDidChange(_ sender: AnyObject?) {
let hue = self.hueSlider?.value ?? 0 let hue = self.hueSlider?.value ?? 0
CoreStore.perform( ColorsDemo.stack.perform(
asynchronous: { [weak self] (transaction) in asynchronous: { [weak self] (transaction) in
if let palette = transaction.edit(self?.monitor?.object) { if let palette = transaction.edit(self?.monitor?.object) {
palette.hue = Int32(hue) palette.hue .= Int(hue)
} }
}, },
completion: { _ in } completion: { _ in }
@@ -136,12 +136,12 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
@IBAction dynamic func saturationSliderValueDidChange(_ sender: AnyObject?) { @IBAction dynamic func saturationSliderValueDidChange(_ sender: AnyObject?) {
let saturation = self.saturationSlider?.value ?? 0 let saturation = self.saturationSlider?.value ?? 0
CoreStore.perform( ColorsDemo.stack.perform(
asynchronous: { [weak self] (transaction) in asynchronous: { [weak self] (transaction) in
if let palette = transaction.edit(self?.monitor?.object) { if let palette = transaction.edit(self?.monitor?.object) {
palette.saturation = saturation palette.saturation .= saturation
} }
}, },
completion: { _ in } completion: { _ in }
@@ -151,12 +151,12 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
@IBAction dynamic func brightnessSliderValueDidChange(_ sender: AnyObject?) { @IBAction dynamic func brightnessSliderValueDidChange(_ sender: AnyObject?) {
let brightness = self.brightnessSlider?.value ?? 0 let brightness = self.brightnessSlider?.value ?? 0
CoreStore.perform( ColorsDemo.stack.perform(
asynchronous: { [weak self] (transaction) in asynchronous: { [weak self] (transaction) in
if let palette = transaction.edit(self?.monitor?.object) { if let palette = transaction.edit(self?.monitor?.object) {
palette.brightness = brightness palette.brightness .= brightness
} }
}, },
completion: { _ in } completion: { _ in }
@@ -165,7 +165,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
@IBAction dynamic func deleteBarButtonTapped(_ sender: AnyObject?) { @IBAction dynamic func deleteBarButtonTapped(_ sender: AnyObject?) {
CoreStore.perform( ColorsDemo.stack.perform(
asynchronous: { [weak self] (transaction) in asynchronous: { [weak self] (transaction) in
transaction.delete(self?.monitor?.object) transaction.delete(self?.monitor?.object)
@@ -176,7 +176,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
func reloadPaletteInfo(_ palette: Palette, changedKeys: Set<String>?) { func reloadPaletteInfo(_ palette: Palette, changedKeys: Set<String>?) {
self.colorNameLabel?.text = palette.colorName self.colorNameLabel?.text = palette.colorName.value
let color = palette.color let color = palette.color
self.colorNameLabel?.textColor = color self.colorNameLabel?.textColor = color
@@ -184,17 +184,17 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
self.hsbLabel?.text = palette.colorText self.hsbLabel?.text = palette.colorText
if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.hue)) == true { if changedKeys == nil || changedKeys?.contains(Palette.keyPath{ $0.hue }) == true {
self.hueSlider?.value = Float(palette.hue) self.hueSlider?.value = Float(palette.hue.value)
} }
if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.saturation)) == true { if changedKeys == nil || changedKeys?.contains(Palette.keyPath{ $0.saturation }) == true {
self.saturationSlider?.value = palette.saturation self.saturationSlider?.value = palette.saturation.value
} }
if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.brightness)) == true { if changedKeys == nil || changedKeys?.contains(Palette.keyPath{ $0.brightness }) == true {
self.brightnessSlider?.value = palette.brightness self.brightnessSlider?.value = palette.brightness.value
} }
} }
} }

View File

@@ -14,64 +14,65 @@ import CoreStore
// MARK: - Palette // MARK: - Palette
class Palette: NSManagedObject { final class Palette: CoreStoreObject {
@NSManaged var hue: Int32
@NSManaged var saturation: Float
@NSManaged var brightness: Float
@objc dynamic var colorName: String { let hue = Value.Required<Int>("hue")
let saturation = Value.Required<Float>("saturation")
let brightness = Value.Required<Float>("brightness")
let colorName = Value.Optional<String>(
"colorName",
isTransient: true,
customGetter: Palette.getCachedColorName
)
private static func getCachedColorName(_ instance: Palette, _ getValue: () -> String?) -> String? {
get { if let colorName = getValue() {
let KVCKey = #keyPath(Palette.colorName)
if let colorName = self.getValue(forKvcKey: KVCKey) as? String {
return colorName
}
let colorName: String
switch self.hue % 360 {
case 0 ..< 20: colorName = "Lower Reds"
case 20 ..< 57: colorName = "Oranges and Browns"
case 57 ..< 90: colorName = "Yellow-Greens"
case 90 ..< 159: colorName = "Greens"
case 159 ..< 197: colorName = "Blue-Greens"
case 197 ..< 241: colorName = "Blues"
case 241 ..< 297: colorName = "Violets"
case 297 ..< 331: colorName = "Magentas"
default: colorName = "Upper Reds"
}
self.setPrimitiveValue(colorName, forKey: KVCKey)
return colorName return colorName
} }
set {
let colorName: String
switch instance.hue.value % 360 {
self.setValue(newValue.cs_toImportableNativeType(), forKvcKey: #keyPath(Palette.colorName)) case 0 ..< 20: colorName = "Lower Reds"
case 20 ..< 57: colorName = "Oranges and Browns"
case 57 ..< 90: colorName = "Yellow-Greens"
case 90 ..< 159: colorName = "Greens"
case 159 ..< 197: colorName = "Blue-Greens"
case 197 ..< 241: colorName = "Blues"
case 241 ..< 297: colorName = "Violets"
case 297 ..< 331: colorName = "Magentas"
default: colorName = "Upper Reds"
} }
instance.colorName.primitiveValue = colorName
return colorName
} }
}
extension Palette {
var color: UIColor { var color: UIColor {
return UIColor( return UIColor(
hue: CGFloat(self.hue) / 360.0, hue: CGFloat(self.hue.value) / 360.0,
saturation: CGFloat(self.saturation), saturation: CGFloat(self.saturation.value),
brightness: CGFloat(self.brightness), brightness: CGFloat(self.brightness.value),
alpha: 1.0 alpha: 1.0
) )
} }
var colorText: String { var colorText: String {
return "H: \(self.hue)˚, S: \(round(self.saturation * 100.0))%, B: \(round(self.brightness * 100.0))%" return "H: \(self.hue.value)˚, S: \(round(self.saturation.value * 100.0))%, B: \(round(self.brightness.value * 100.0))%"
} }
func setInitialValues() { func setInitialValues(in transaction: BaseDataTransaction) {
self.hue = Int32(arc4random_uniform(360)) self.hue .= Int(arc4random_uniform(360))
self.saturation = 1.0 self.saturation .= Float(1.0)
self.brightness = Float(arc4random_uniform(70) + 30) / 100.0 self.brightness .= Float(arc4random_uniform(70) + 30) / 100.0
} }
} }