Magical NSFetchedResultsController bugfix....

This commit is contained in:
John Estropia
2016-09-09 12:49:10 +09:00
parent 82de482191
commit 3f28198552
19 changed files with 150 additions and 158 deletions

View File

@@ -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

View File

@@ -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>(),

View File

@@ -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))
) )
] ]

View File

@@ -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

View File

@@ -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

View File

@@ -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")
} }
} }

View File

@@ -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)
}
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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,

View File

@@ -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?
} }

View File

@@ -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)
}
} }
} }

View File

@@ -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) }

View File

@@ -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
} }
} }

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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
}() }()

View File

@@ -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

View File

@@ -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
) )
} }