workaround an NSFetchedResultsController bug in Xcode 7 targeted on iOS 8 devices where errant index paths cause crashes

This commit is contained in:
John Estropia
2015-09-10 16:57:35 +09:00
parent 4c6bc4f494
commit 5461bb0736
4 changed files with 200 additions and 126 deletions

View File

@@ -955,7 +955,7 @@ extension ListMonitor: FetchedResultsControllerHandler {
// MARK: FetchedResultsControllerHandler
private func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
internal func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
@@ -990,7 +990,6 @@ extension ListMonitor: FetchedResultsControllerHandler {
)
case .Move:
CoreStore.log(.Notice, message: "\(indexPath!) - \(newIndexPath!)")
NSNotificationCenter.defaultCenter().postNotificationName(
ListMonitorDidMoveObjectNotification,
object: self,
@@ -1003,7 +1002,7 @@ extension ListMonitor: FetchedResultsControllerHandler {
}
}
private func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
internal func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
switch type {
@@ -1032,7 +1031,7 @@ extension ListMonitor: FetchedResultsControllerHandler {
}
}
private func controllerWillChangeContent(controller: NSFetchedResultsController) {
internal func controllerWillChangeContent(controller: NSFetchedResultsController) {
self.taskGroup.enter()
NSNotificationCenter.defaultCenter().postNotificationName(
@@ -1041,7 +1040,7 @@ extension ListMonitor: FetchedResultsControllerHandler {
)
}
private func controllerDidChangeContent(controller: NSFetchedResultsController) {
internal func controllerDidChangeContent(controller: NSFetchedResultsController) {
NSNotificationCenter.defaultCenter().postNotificationName(
ListMonitorDidChangeListNotification,
@@ -1050,80 +1049,13 @@ extension ListMonitor: FetchedResultsControllerHandler {
self.taskGroup.leave()
}
private func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? {
internal func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? {
return self.sectionIndexTransformer(sectionName: sectionName)
}
}
// MARK: - FetchedResultsControllerHandler
private protocol FetchedResultsControllerHandler: class {
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
func controllerWillChangeContent(controller: NSFetchedResultsController)
func controllerDidChangeContent(controller: NSFetchedResultsController)
func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String?
}
// MARK: - FetchedResultsControllerDelegate
private final class FetchedResultsControllerDelegate: NSObject, NSFetchedResultsControllerDelegate {
// MARK: NSFetchedResultsControllerDelegate
@objc dynamic func controllerWillChangeContent(controller: NSFetchedResultsController) {
self.handler?.controllerWillChangeContent(controller)
}
@objc dynamic func controllerDidChangeContent(controller: NSFetchedResultsController) {
self.handler?.controllerDidChangeContent(controller)
}
@objc dynamic func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
self.handler?.controller(controller, didChangeObject: anObject, atIndexPath: indexPath, forChangeType: type, newIndexPath: newIndexPath)
}
@objc dynamic func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
self.handler?.controller(controller, didChangeSection: sectionInfo, atIndex: sectionIndex, forChangeType: type)
}
@objc dynamic func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String) -> String? {
return self.handler?.controller(controller, sectionIndexTitleForSectionName: sectionName)
}
// MARK: Private
weak var handler: FetchedResultsControllerHandler?
weak var fetchedResultsController: NSFetchedResultsController? {
didSet {
oldValue?.delegate = nil
self.fetchedResultsController?.delegate = self
}
}
deinit {
self.fetchedResultsController?.delegate = nil
}
}
private let ListMonitorWillChangeListNotification = "ListMonitorWillChangeListNotification"
private let ListMonitorDidChangeListNotification = "ListMonitorDidChangeListNotification"
private let ListMonitorWillRefetchListNotification = "ListMonitorWillRefetchListNotification"

View File

@@ -268,7 +268,17 @@ extension ObjectMonitor: FetchedResultsControllerHandler {
// MARK: FetchedResultsControllerHandler
private func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
internal func controllerWillChangeContent(controller: NSFetchedResultsController) {
NSNotificationCenter.defaultCenter().postNotificationName(
ObjectMonitorWillChangeObjectNotification,
object: self
)
}
internal func controllerDidChangeContent(controller: NSFetchedResultsController) { }
internal func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
@@ -279,7 +289,7 @@ extension ObjectMonitor: FetchedResultsControllerHandler {
userInfo: [UserInfoKeyObject: anObject]
)
case .Update, .Move where indexPath == newIndexPath:
case .Update:
NSNotificationCenter.defaultCenter().postNotificationName(
ObjectMonitorDidUpdateObjectNotification,
object: self,
@@ -291,58 +301,11 @@ extension ObjectMonitor: FetchedResultsControllerHandler {
}
}
private func controllerWillChangeContent(controller: NSFetchedResultsController) {
internal func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { }
internal func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? {
NSNotificationCenter.defaultCenter().postNotificationName(
ObjectMonitorWillChangeObjectNotification,
object: self
)
}
}
// MARK: - FetchedResultsControllerHandler
private protocol FetchedResultsControllerHandler: class {
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
func controllerWillChangeContent(controller: NSFetchedResultsController)
}
// MARK: - FetchedResultsControllerDelegate
private final class FetchedResultsControllerDelegate: NSObject, NSFetchedResultsControllerDelegate {
// MARK: NSFetchedResultsControllerDelegate
@objc dynamic func controllerWillChangeContent(controller: NSFetchedResultsController) {
self.handler?.controllerWillChangeContent(controller)
}
@objc dynamic func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
self.handler?.controller(controller, didChangeObject: anObject, atIndexPath: indexPath, forChangeType: type, newIndexPath: newIndexPath)
}
// MARK: Private
weak var handler: FetchedResultsControllerHandler?
weak var fetchedResultsController: NSFetchedResultsController? {
didSet {
oldValue?.delegate = nil
self.fetchedResultsController?.delegate = self
}
}
deinit {
self.fetchedResultsController?.delegate = nil
return sectionName
}
}