mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-28 20:31:49 +01:00
Magical NSFetchedResultsController bugfix....
This commit is contained in:
@@ -18,7 +18,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
|
|
||||||
var window: UIWindow?
|
var window: UIWindow?
|
||||||
|
|
||||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
|
||||||
|
|
||||||
application.statusBarStyle = .lightContent
|
application.statusBarStyle = .lightContent
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ private struct Static {
|
|||||||
|
|
||||||
transaction.deleteAll(From<TimeZone>())
|
transaction.deleteAll(From<TimeZone>())
|
||||||
|
|
||||||
for name in Foundation.TimeZone.knownTimeZoneNames {
|
for name in NSTimeZone.knownTimeZoneNames {
|
||||||
|
|
||||||
let rawTimeZone = Foundation.TimeZone(name: name)!
|
let rawTimeZone = NSTimeZone(name: name)!
|
||||||
let cachedTimeZone = transaction.create(Into<TimeZone>())
|
let cachedTimeZone = transaction.create(Into<TimeZone>())
|
||||||
|
|
||||||
cachedTimeZone.name = rawTimeZone.name
|
cachedTimeZone.name = rawTimeZone.name
|
||||||
@@ -73,13 +73,13 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
|||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
|
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||||
|
|
||||||
super.prepare(for: segue, sender: sender)
|
super.prepare(for: segue, sender: sender)
|
||||||
|
|
||||||
if let indexPath = sender as? IndexPath {
|
if let indexPath = sender as? IndexPath {
|
||||||
|
|
||||||
switch segue.destinationViewController {
|
switch segue.destination {
|
||||||
|
|
||||||
case let controller as FetchingResultsViewController:
|
case let controller as FetchingResultsViewController:
|
||||||
let item = self.fetchingItems[indexPath.row]
|
let item = self.fetchingItems[indexPath.row]
|
||||||
@@ -222,7 +222,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
|||||||
private let queryingItems = [
|
private let queryingItems = [
|
||||||
(
|
(
|
||||||
title: "Number of Time Zones",
|
title: "Number of Time Zones",
|
||||||
query: { () -> AnyObject in
|
query: { () -> Any in
|
||||||
|
|
||||||
return Static.timeZonesStack.queryValue(
|
return Static.timeZonesStack.queryValue(
|
||||||
From<TimeZone>(),
|
From<TimeZone>(),
|
||||||
@@ -232,7 +232,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
title: "Abbreviation For Tokyo's Time Zone",
|
title: "Abbreviation For Tokyo's Time Zone",
|
||||||
query: { () -> AnyObject in
|
query: { () -> Any in
|
||||||
|
|
||||||
return Static.timeZonesStack.queryValue(
|
return Static.timeZonesStack.queryValue(
|
||||||
From<TimeZone>(),
|
From<TimeZone>(),
|
||||||
@@ -243,7 +243,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
title: "All Abbreviations",
|
title: "All Abbreviations",
|
||||||
query: { () -> AnyObject in
|
query: { () -> Any in
|
||||||
|
|
||||||
return Static.timeZonesStack.queryAttributes(
|
return Static.timeZonesStack.queryAttributes(
|
||||||
From<TimeZone>(),
|
From<TimeZone>(),
|
||||||
@@ -254,7 +254,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
title: "Number of Countries per Time Zone",
|
title: "Number of Countries per Time Zone",
|
||||||
query: { () -> AnyObject in
|
query: { () -> Any in
|
||||||
|
|
||||||
return Static.timeZonesStack.queryAttributes(
|
return Static.timeZonesStack.queryAttributes(
|
||||||
From<TimeZone>(),
|
From<TimeZone>(),
|
||||||
@@ -266,7 +266,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
title: "Number of Countries with Summer Time",
|
title: "Number of Countries with Summer Time",
|
||||||
query: { () -> AnyObject in
|
query: { () -> Any in
|
||||||
|
|
||||||
return Static.timeZonesStack.queryAttributes(
|
return Static.timeZonesStack.queryAttributes(
|
||||||
From<TimeZone>(),
|
From<TimeZone>(),
|
||||||
|
|||||||
@@ -12,23 +12,23 @@ class QueryingResultsViewController: UITableViewController {
|
|||||||
|
|
||||||
// MARK: Public
|
// MARK: Public
|
||||||
|
|
||||||
func set(value: AnyObject?, title: String) {
|
func set(value: Any?, title: String) {
|
||||||
|
|
||||||
switch value {
|
switch value {
|
||||||
|
|
||||||
case (let array as [AnyObject])?:
|
case (let array as [Any])?:
|
||||||
self.values = array.map { (item: AnyObject) -> (title: String, detail: String) in
|
self.values = array.map { (item: Any) -> (title: String, detail: String) in
|
||||||
(
|
(
|
||||||
title: item.description,
|
title: String(describing: item),
|
||||||
detail: String(reflecting: item.dynamicType)
|
detail: String(reflecting: type(of: item))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case let item?:
|
case let item?:
|
||||||
self.values = [
|
self.values = [
|
||||||
(
|
(
|
||||||
title: item.description,
|
title: String(describing: item),
|
||||||
detail: String(reflecting: item.dynamicType)
|
detail: String(reflecting: type(of: item))
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -14,17 +14,17 @@ private struct Static {
|
|||||||
|
|
||||||
enum Filter: String {
|
enum Filter: String {
|
||||||
|
|
||||||
case All = "All Colors"
|
case all = "All Colors"
|
||||||
case Light = "Light Colors"
|
case light = "Light Colors"
|
||||||
case Dark = "Dark Colors"
|
case dark = "Dark Colors"
|
||||||
|
|
||||||
func next() -> Filter {
|
func next() -> Filter {
|
||||||
|
|
||||||
switch self {
|
switch self {
|
||||||
|
|
||||||
case All: return .Light
|
case .all: return .light
|
||||||
case Light: return .Dark
|
case .light: return .dark
|
||||||
case Dark: return .All
|
case .dark: return .all
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,14 +32,14 @@ private struct Static {
|
|||||||
|
|
||||||
switch self {
|
switch self {
|
||||||
|
|
||||||
case .All: return Where(true)
|
case .all: return Where(true)
|
||||||
case .Light: return Where("brightness >= 0.9")
|
case .light: return Where("brightness >= 0.9")
|
||||||
case .Dark: return Where("brightness <= 0.4")
|
case .dark: return Where("brightness <= 0.4")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static var filter = Filter.All {
|
static var filter = Filter.all {
|
||||||
|
|
||||||
didSet {
|
didSet {
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
|||||||
|
|
||||||
let navigationItem = self.navigationItem
|
let navigationItem = self.navigationItem
|
||||||
navigationItem.leftBarButtonItems = [
|
navigationItem.leftBarButtonItems = [
|
||||||
self.editButtonItem(),
|
self.editButtonItem,
|
||||||
UIBarButtonItem(
|
UIBarButtonItem(
|
||||||
barButtonSystemItem: .trash,
|
barButtonSystemItem: .trash,
|
||||||
target: self,
|
target: self,
|
||||||
@@ -115,11 +115,11 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
|||||||
self.setTable(enabled: !Static.palettes.isPendingRefetch)
|
self.setTable(enabled: !Static.palettes.isPendingRefetch)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
|
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||||
|
|
||||||
super.prepare(for: segue, sender: sender)
|
super.prepare(for: segue, sender: sender)
|
||||||
|
|
||||||
switch (segue.identifier, segue.destinationViewController, sender) {
|
switch (segue.identifier, segue.destination, sender) {
|
||||||
|
|
||||||
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
|
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
|
||||||
destinationViewController.palette = palette
|
destinationViewController.palette = palette
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
|||||||
self.colorView?.alpha = 0.3
|
self.colorView?.alpha = 0.3
|
||||||
|
|
||||||
self.hsbLabel?.text = "Deleted"
|
self.hsbLabel?.text = "Deleted"
|
||||||
self.hsbLabel?.textColor = UIColor.red()
|
self.hsbLabel?.textColor = UIColor.red
|
||||||
|
|
||||||
self.hueSlider?.isEnabled = false
|
self.hueSlider?.isEnabled = false
|
||||||
self.saturationSlider?.isEnabled = false
|
self.saturationSlider?.isEnabled = false
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
|||||||
|
|
||||||
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||||
|
|
||||||
GCDQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
|
||||||
let levelString: String
|
let levelString: String
|
||||||
switch level {
|
switch level {
|
||||||
@@ -61,15 +61,15 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
|||||||
case .warning: levelString = "Warning"
|
case .warning: levelString = "Warning"
|
||||||
case .fatal: levelString = "Fatal"
|
case .fatal: levelString = "Fatal"
|
||||||
}
|
}
|
||||||
self?.textView?.insertText("\((String(fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
|
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||||
|
|
||||||
GCDQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
|
||||||
self?.textView?.insertText("\((String(fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
|
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,9 +81,9 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let messageString = message()
|
let messageString = message()
|
||||||
GCDQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
|
||||||
self?.textView?.insertText("\((String(fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
|
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import CoreStore
|
|||||||
|
|
||||||
// MARK: - MigrationsDemoViewController
|
// MARK: - MigrationsDemoViewController
|
||||||
|
|
||||||
class MigrationsDemoViewController: UIViewController {
|
class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewDataSource, UITableViewDelegate {
|
||||||
|
|
||||||
// MARK: UIViewController
|
// MARK: UIViewController
|
||||||
|
|
||||||
@@ -72,6 +72,71 @@ class MigrationsDemoViewController: UIViewController {
|
|||||||
self.selectModelVersion(modelMetadata)
|
self.selectModelVersion(modelMetadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: ListObserver
|
||||||
|
|
||||||
|
func listMonitorWillChange(_ monitor: ListMonitor<NSManagedObject>) { }
|
||||||
|
|
||||||
|
func listMonitorDidChange(_ monitor: ListMonitor<NSManagedObject>) {
|
||||||
|
|
||||||
|
if self.lastSelectedIndexPath == nil,
|
||||||
|
let numberOfObjectsInSection = self.listMonitor?.numberOfObjectsInSection(0),
|
||||||
|
numberOfObjectsInSection > 0 {
|
||||||
|
|
||||||
|
self.tableView?.reloadData()
|
||||||
|
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: false)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
self.updateDisplay(reloadData: true, scrollToSelection: true, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: UITableViewDataSource
|
||||||
|
|
||||||
|
@objc dynamic func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
|
||||||
|
return self.listMonitor?.numberOfObjectsInSection(0) ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc dynamic func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
|
||||||
|
let cell = tableView.dequeueReusableCell(withIdentifier: "OrganismTableViewCell", for: indexPath) as! OrganismTableViewCell
|
||||||
|
|
||||||
|
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
|
||||||
|
cell.dnaLabel?.text = "DNA: \(dna)"
|
||||||
|
cell.mutateButtonHandler = { [weak self] _ -> Void in
|
||||||
|
|
||||||
|
guard let `self` = self,
|
||||||
|
let dataStack = self.dataStack,
|
||||||
|
let organism = self.listMonitor?[indexPath] else {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
|
||||||
|
self.setEnabled(false)
|
||||||
|
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||||
|
|
||||||
|
let organism = transaction.edit(organism) as! OrganismProtocol
|
||||||
|
organism.mutate()
|
||||||
|
|
||||||
|
transaction.commit { _ -> Void in
|
||||||
|
|
||||||
|
self?.setEnabled(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: UITableViewDelegate
|
||||||
|
|
||||||
|
@objc dynamic func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
|
||||||
|
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
@@ -176,8 +241,7 @@ class MigrationsDemoViewController: UIViewController {
|
|||||||
|
|
||||||
let count = dataStack.queryValue(
|
let count = dataStack.queryValue(
|
||||||
From(model.entityType),
|
From(model.entityType),
|
||||||
Select<Int>(.count("dna"))
|
Select<Int>(.count("dna")))!
|
||||||
)
|
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
|
|
||||||
self.setEnabled(true)
|
self.setEnabled(true)
|
||||||
@@ -287,7 +351,7 @@ class MigrationsDemoViewController: UIViewController {
|
|||||||
|
|
||||||
for property in organism.entity.properties {
|
for property in organism.entity.properties {
|
||||||
|
|
||||||
let value: AnyObject = organism.value(forKey: property.name) ?? NSNull()
|
let value = organism.value(forKey: property.name) ?? NSNull()
|
||||||
lines.append("\(property.name): \(value)")
|
lines.append("\(property.name): \(value)")
|
||||||
}
|
}
|
||||||
organismType = organism.entity.managedObjectClassName
|
organismType = organism.entity.managedObjectClassName
|
||||||
@@ -321,78 +385,3 @@ class MigrationsDemoViewController: UIViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - MigrationsDemoViewController: ListObserver
|
|
||||||
|
|
||||||
extension MigrationsDemoViewController: ListObserver {
|
|
||||||
|
|
||||||
// MARK: ListObserver
|
|
||||||
|
|
||||||
func listMonitorWillChange(_ monitor: ListMonitor<NSManagedObject>) { }
|
|
||||||
|
|
||||||
func listMonitorDidChange(_ monitor: ListMonitor<NSManagedObject>) {
|
|
||||||
|
|
||||||
if self.lastSelectedIndexPath == nil && self.listMonitor?.numberOfObjectsInSection(0) > 0 {
|
|
||||||
|
|
||||||
self.tableView?.reloadData()
|
|
||||||
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: false)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
self.updateDisplay(reloadData: true, scrollToSelection: true, animated: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - MigrationsDemoViewController: UITableViewDataSource, UITableViewDelegate
|
|
||||||
|
|
||||||
extension MigrationsDemoViewController: UITableViewDataSource, UITableViewDelegate {
|
|
||||||
|
|
||||||
// MARK: UITableViewDataSource
|
|
||||||
|
|
||||||
@objc dynamic func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
||||||
|
|
||||||
return self.listMonitor?.numberOfObjectsInSection(0) ?? 0
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc dynamic func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
||||||
|
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "OrganismTableViewCell", for: indexPath) as! OrganismTableViewCell
|
|
||||||
|
|
||||||
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
|
|
||||||
cell.dnaLabel?.text = "DNA: \(dna)"
|
|
||||||
cell.mutateButtonHandler = { [weak self] _ -> Void in
|
|
||||||
|
|
||||||
guard let `self` = self,
|
|
||||||
let dataStack = self.dataStack,
|
|
||||||
let organism = self.listMonitor?[indexPath] else {
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
|
|
||||||
self.setEnabled(false)
|
|
||||||
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in
|
|
||||||
|
|
||||||
let organism = transaction.edit(organism) as! OrganismProtocol
|
|
||||||
organism.mutate()
|
|
||||||
|
|
||||||
transaction.commit { _ -> Void in
|
|
||||||
|
|
||||||
self?.setEnabled(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cell
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: UITableViewDelegate
|
|
||||||
|
|
||||||
@objc dynamic func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
||||||
|
|
||||||
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
|||||||
|
|
||||||
if let mapView = self.mapView {
|
if let mapView = self.mapView {
|
||||||
|
|
||||||
mapView.removeAnnotations(mapView.annotations ?? [])
|
mapView.removeAnnotations(mapView.annotations)
|
||||||
mapView.addAnnotation(object)
|
mapView.addAnnotation(object)
|
||||||
mapView.setCenter(object.coordinate, animated: true)
|
mapView.setCenter(object.coordinate, animated: true)
|
||||||
mapView.selectAnnotation(object, animated: true)
|
mapView.selectAnnotation(object, animated: true)
|
||||||
|
|||||||
@@ -97,13 +97,13 @@ class BaseTestCase: XCTestCase {
|
|||||||
@nonobjc
|
@nonobjc
|
||||||
func checkExpectationsImmediately() {
|
func checkExpectationsImmediately() {
|
||||||
|
|
||||||
self.waitForExpectations(timeout: 0, handler: nil)
|
self.waitForExpectations(timeout: 0, handler: { _ in })
|
||||||
}
|
}
|
||||||
|
|
||||||
@nonobjc
|
@nonobjc
|
||||||
func waitAndCheckExpectations() {
|
func waitAndCheckExpectations() {
|
||||||
|
|
||||||
self.waitForExpectations(timeout: 10, handler: nil)
|
self.waitForExpectations(timeout: 10, handler: {_ in })
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: XCTestCase
|
// MARK: XCTestCase
|
||||||
|
|||||||
@@ -1170,7 +1170,7 @@ class QueryTests: BaseTestDataTestCase {
|
|||||||
]
|
]
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let values: [NSDictionary]? = stack.queryAttributes(
|
let values = stack.queryAttributes(
|
||||||
from,
|
from,
|
||||||
Select(
|
Select(
|
||||||
"testBoolean",
|
"testBoolean",
|
||||||
@@ -1185,7 +1185,7 @@ class QueryTests: BaseTestDataTestCase {
|
|||||||
)
|
)
|
||||||
XCTAssertNotNil(values)
|
XCTAssertNotNil(values)
|
||||||
XCTAssertEqual(
|
XCTAssertEqual(
|
||||||
values!,
|
values as Any as! [NSDictionary],
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
"testBoolean": NSNumber(value: false),
|
"testBoolean": NSNumber(value: false),
|
||||||
@@ -1221,7 +1221,7 @@ class QueryTests: BaseTestDataTestCase {
|
|||||||
let queryClauses: [QueryClause] = []
|
let queryClauses: [QueryClause] = []
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let values: [NSDictionary]? = stack.queryAttributes(
|
let values = stack.queryAttributes(
|
||||||
from,
|
from,
|
||||||
Select(
|
Select(
|
||||||
.sum("testBoolean"),
|
.sum("testBoolean"),
|
||||||
@@ -1234,7 +1234,7 @@ class QueryTests: BaseTestDataTestCase {
|
|||||||
)
|
)
|
||||||
XCTAssertNotNil(values)
|
XCTAssertNotNil(values)
|
||||||
XCTAssertEqual(
|
XCTAssertEqual(
|
||||||
values!,
|
values as Any as! [NSDictionary],
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
"sum(testBoolean)": 3,
|
"sum(testBoolean)": 3,
|
||||||
@@ -1248,7 +1248,7 @@ class QueryTests: BaseTestDataTestCase {
|
|||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let values: [NSDictionary]? = stack.queryAttributes(
|
let values = stack.queryAttributes(
|
||||||
from,
|
from,
|
||||||
Select(
|
Select(
|
||||||
.sum("testBoolean", as: "testSum"),
|
.sum("testBoolean", as: "testSum"),
|
||||||
@@ -1261,7 +1261,7 @@ class QueryTests: BaseTestDataTestCase {
|
|||||||
)
|
)
|
||||||
XCTAssertNotNil(values)
|
XCTAssertNotNil(values)
|
||||||
XCTAssertEqual(
|
XCTAssertEqual(
|
||||||
values!,
|
values as Any as! [NSDictionary],
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
"testSum": 3,
|
"testSum": 3,
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public enum CoreStore {
|
|||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private static let defaultStackBarrierQueue = DispatchQueue(concurrentWith: "com.coreStore.defaultStackBarrierQueue")
|
private static let defaultStackBarrierQueue = DispatchQueue.concurrent("com.coreStore.defaultStackBarrierQueue")
|
||||||
|
|
||||||
private static var defaultStackInstance: DataStack?
|
private static var defaultStackInstance: DataStack?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,9 +45,18 @@ internal final class CoreStoreFetchRequest<T: NSFetchRequestResult>: NSFetchRequ
|
|||||||
// MARK: NSFetchRequest
|
// MARK: NSFetchRequest
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
override var affectedStores: [NSPersistentStore]? {
|
dynamic override var affectedStores: [NSPersistentStore]? {
|
||||||
|
|
||||||
get { return super.affectedStores }
|
get {
|
||||||
set { super.affectedStores = newValue }
|
|
||||||
|
return super.affectedStores
|
||||||
|
// let affectedStores: NSArray? = super.affectedStores.flatMap({ NSArray(array: $0) } )
|
||||||
|
// return affectedStores as? [NSPersistentStore]
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
|
||||||
|
super.affectedStores = newValue
|
||||||
|
// super.affectedStores = newValue.flatMap(Array.init)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ import Foundation
|
|||||||
|
|
||||||
internal extension DispatchQueue {
|
internal extension DispatchQueue {
|
||||||
|
|
||||||
internal convenience init(serialWith label: String, qos: DispatchQoS = .default) {
|
@nonobjc
|
||||||
|
internal static func serial(_ label: String, qos: DispatchQoS = .default) -> DispatchQueue {
|
||||||
|
|
||||||
self.init(
|
return DispatchQueue(
|
||||||
label: label,
|
label: label,
|
||||||
qos: qos,
|
qos: qos,
|
||||||
attributes: [],
|
attributes: [],
|
||||||
@@ -41,9 +42,10 @@ internal extension DispatchQueue {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal convenience init(concurrentWith label: String, qos: DispatchQoS = .default) {
|
@nonobjc
|
||||||
|
internal static func concurrent(_ label: String, qos: DispatchQoS = .default) -> DispatchQueue {
|
||||||
|
|
||||||
self.init(
|
return DispatchQueue(
|
||||||
label: label,
|
label: label,
|
||||||
qos: qos,
|
qos: qos,
|
||||||
attributes: .concurrent,
|
attributes: .concurrent,
|
||||||
@@ -52,6 +54,7 @@ internal extension DispatchQueue {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@nonobjc
|
||||||
internal func cs_isCurrentExecutionContext() -> Bool {
|
internal func cs_isCurrentExecutionContext() -> Bool {
|
||||||
|
|
||||||
let specific = ObjectIdentifier(self)
|
let specific = ObjectIdentifier(self)
|
||||||
@@ -60,21 +63,25 @@ internal extension DispatchQueue {
|
|||||||
return DispatchQueue.getSpecific(key: Static.specificKey) == specific
|
return DispatchQueue.getSpecific(key: Static.specificKey) == specific
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@nonobjc
|
||||||
internal func cs_sync<T>(_ closure: () throws -> T) rethrows -> T {
|
internal func cs_sync<T>(_ closure: () throws -> T) rethrows -> T {
|
||||||
|
|
||||||
return try self.sync { try autoreleasepool(invoking: closure) }
|
return try self.sync { try autoreleasepool(invoking: closure) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@nonobjc
|
||||||
internal func cs_async(_ closure: @escaping () -> Void) {
|
internal func cs_async(_ closure: @escaping () -> Void) {
|
||||||
|
|
||||||
self.async { autoreleasepool(invoking: closure) }
|
self.async { autoreleasepool(invoking: closure) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@nonobjc
|
||||||
internal func cs_barrierSync<T>(_ closure: () throws -> T) rethrows -> T {
|
internal func cs_barrierSync<T>(_ closure: () throws -> T) rethrows -> T {
|
||||||
|
|
||||||
return try self.sync(flags: .barrier) { try autoreleasepool(invoking: closure) }
|
return try self.sync(flags: .barrier) { try autoreleasepool(invoking: closure) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@nonobjc
|
||||||
internal func cs_barrierAsync(_ closure: @escaping () -> Void) {
|
internal func cs_barrierAsync(_ closure: @escaping () -> Void) {
|
||||||
|
|
||||||
self.async(flags: .barrier) { autoreleasepool(invoking: closure) }
|
self.async(flags: .barrier) { autoreleasepool(invoking: closure) }
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let actualType = NSFetchedResultsChangeType(rawValue: type.rawValue) else {
|
guard var actualType = NSFetchedResultsChangeType(rawValue: type.rawValue) else {
|
||||||
|
|
||||||
// This fix is for a bug where iOS passes 0 for NSFetchedResultsChangeType, but this is not a valid enum case.
|
// This fix is for a bug where iOS passes 0 for NSFetchedResultsChangeType, but this is not a valid enum case.
|
||||||
// Swift will then always execute the first case of the switch causing strange behaviour.
|
// Swift will then always execute the first case of the switch causing strange behaviour.
|
||||||
@@ -123,19 +123,12 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
|
|||||||
|
|
||||||
if #available(iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
|
if #available(iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
|
||||||
|
|
||||||
// iOS 10 is better, but still not perfect...
|
// I don't know if iOS 10 even attempted to fix this mess...
|
||||||
if case .update = actualType,
|
if case .update = actualType,
|
||||||
let indexPath = indexPath,
|
indexPath != nil,
|
||||||
let newIndexPath = newIndexPath {
|
newIndexPath != nil {
|
||||||
|
|
||||||
self.handler?.controller(
|
actualType = .move
|
||||||
controller,
|
|
||||||
didChangeObject: anObject,
|
|
||||||
atIndexPath: indexPath,
|
|
||||||
forChangeType: .move,
|
|
||||||
newIndexPath: newIndexPath
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ internal extension NSManagedObjectContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@nonobjc
|
@nonobjc
|
||||||
internal func saveAsynchronouslyWithCompletion(_ completion: ((_ result: SaveResult) -> Void) = { _ in }) {
|
internal func saveAsynchronouslyWithCompletion(_ completion: @escaping ((_ result: SaveResult) -> Void) = { _ in }) {
|
||||||
|
|
||||||
self.perform {
|
self.perform {
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ internal final class NotificationObserver {
|
|||||||
|
|
||||||
let observer: NSObjectProtocol
|
let observer: NSObjectProtocol
|
||||||
|
|
||||||
init(notificationName: Notification.Name, object: AnyObject?, queue: OperationQueue? = nil, closure: @escaping (_ note: Notification) -> Void) {
|
init(notificationName: Notification.Name, object: Any?, queue: OperationQueue? = nil, closure: @escaping (_ note: Notification) -> Void) {
|
||||||
|
|
||||||
self.observer = NotificationCenter.default.addObserver(
|
self.observer = NotificationCenter.default.addObserver(
|
||||||
forName: notificationName,
|
forName: notificationName,
|
||||||
|
|||||||
@@ -385,18 +385,15 @@ public final class DataStack {
|
|||||||
internal let mainContext: NSManagedObjectContext
|
internal let mainContext: NSManagedObjectContext
|
||||||
internal let model: NSManagedObjectModel
|
internal let model: NSManagedObjectModel
|
||||||
internal let migrationChain: MigrationChain
|
internal let migrationChain: MigrationChain
|
||||||
internal let childTransactionQueue = DispatchQueue(serialWith: "com.coreStore.dataStack.childTransactionQueue")
|
internal let childTransactionQueue = DispatchQueue.serial("com.coreStore.dataStack.childTransactionQueue")
|
||||||
internal let storeMetadataUpdateQueue = DispatchQueue(concurrentWith: "com.coreStore.persistentStoreBarrierQueue")
|
internal let storeMetadataUpdateQueue = DispatchQueue.concurrent("com.coreStore.persistentStoreBarrierQueue")
|
||||||
internal let migrationQueue: OperationQueue = {
|
internal let migrationQueue: OperationQueue = {
|
||||||
|
|
||||||
let migrationQueue = OperationQueue()
|
let migrationQueue = OperationQueue()
|
||||||
migrationQueue.maxConcurrentOperationCount = 1
|
migrationQueue.maxConcurrentOperationCount = 1
|
||||||
migrationQueue.name = "com.coreStore.migrationOperationQueue"
|
migrationQueue.name = "com.coreStore.migrationOperationQueue"
|
||||||
migrationQueue.qualityOfService = .utility
|
migrationQueue.qualityOfService = .utility
|
||||||
migrationQueue.underlyingQueue = DispatchQueue(
|
migrationQueue.underlyingQueue = DispatchQueue.serial("com.coreStore.migrationQueue", qos: .userInitiated)
|
||||||
serialWith: "com.coreStore.migrationQueue",
|
|
||||||
qos: .userInitiated
|
|
||||||
)
|
|
||||||
return migrationQueue
|
return migrationQueue
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@@ -451,7 +451,7 @@ public /*abstract*/ class BaseDataTransaction {
|
|||||||
|
|
||||||
internal let context: NSManagedObjectContext
|
internal let context: NSManagedObjectContext
|
||||||
internal let transactionQueue: DispatchQueue
|
internal let transactionQueue: DispatchQueue
|
||||||
internal let childTransactionQueue = DispatchQueue(serialWith: "com.corestore.datastack.childtransactionqueue")
|
internal let childTransactionQueue = DispatchQueue.serial("com.corestore.datastack.childtransactionqueue")
|
||||||
internal let supportsUndo: Bool
|
internal let supportsUndo: Bool
|
||||||
internal let bypassesQueueing: Bool
|
internal let bypassesQueueing: Bool
|
||||||
|
|
||||||
|
|||||||
@@ -69,10 +69,7 @@ public extension DataStack {
|
|||||||
|
|
||||||
return UnsafeDataTransaction(
|
return UnsafeDataTransaction(
|
||||||
mainContext: self.rootSavingContext,
|
mainContext: self.rootSavingContext,
|
||||||
queue: DispatchQueue(
|
queue: DispatchQueue.serial("com.coreStore.dataStack.unsafeTransactionQueue", qos: .userInitiated),
|
||||||
serialWith: "com.coreStore.dataStack.unsafeTransactionQueue",
|
|
||||||
qos: .userInitiated
|
|
||||||
),
|
|
||||||
supportsUndo: supportsUndo
|
supportsUndo: supportsUndo
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user