在 Swift 3 中难以配置 NSFetchedResultsController

Posted

技术标签:

【中文标题】在 Swift 3 中难以配置 NSFetchedResultsController【英文标题】:Difficulty configuring NSFetchedResultsController in Swift 3 【发布时间】:2016-09-22 15:13:55 【问题描述】:

我正在将现有项目从 Swift 2 重构为 Swift 3。在我重构 Core Data 之前,一切都很简单。我能够创建托管对象并将它们保存在managedObjectContext 中,但我很难让NSFetchedResultsController 工作。我查看了this post,但它并没有让我越过终点线。

从 JSON 导入记录后,我使用以下代码验证 managedObjectContext 中有对象:

func recordCount() -> Int 
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "MyEntity")
    let count = try! context.count(for: fetchRequest)
    return count

当我创建fetchedResultsController 时,我遇到了麻烦。我的代码没有崩溃,但它没有返回 NSManagedObjects,尽管存在与我的搜索匹配的对象。

这是我在UIViewController 中创建NSFetchedResultsController 的方式。

class MyViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate 
    // This is set on a prior viewController before segue.
    // I've verified it's not nil
    var selectedEquipmentString: String?

    let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

    lazy var fetchedResultsController: NSFetchedResultsController<MyEntity> = 
        // I've tried altering the syntax of the fetchRequest
        // let fetchRequest: NSFetchRequest<MyEntity> = MyEntity.fetchRequest()
        let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "MyEntity")
        let sortDescriptor = NSSortDescriptor(key: "generalArea", ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]
        fetchRequest.predicate = NSPredicate(format: "equipmentDescription == %@", self.selectedEquipmentString!)
        let frc: NSFetchedResultsController<MyEntity> = NSFetchedResultsController(fetchRequest: fetchRequest as! NSFetchRequest<MyEntity>, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: "generalArea", cacheName: nil)
        frc.delegate = self
        return frc
    ()

    // MARK: - View Lifecycle Methods (abbreviated)
    override func viewDidLoad() 
        super.viewDidLoad()
        // I've tried moving this call to viewWillAppear and viewDidAppear without success
        fetchObjectsFromManagedObjectContext()
    

    // MARK: - Core Data Methods (abbreviated)
    func fetchObjectsFromManagedObjectContext() 
        do 
            try fetchedResultsController.performFetch()
         catch 
            print("error: \(error)")
            return
        
        print ("There are \(fetchedResultsController.fetchedObjects!.count) returned from fetchObjectsFromManagedObjectContext")
    

此代码不会崩溃,但不会从 fetchRequest 返回任何记录。我能够通过谓词中的拼写错误强制崩溃,但是如果没有拼写错误,尽管对象与谓词匹配,但没有返回任何对象。

我欢迎任何建议:我的错误在哪里。我放心,我知道这将是我的一个非常愚蠢的疏忽。感谢您的阅读。

【问题讨论】:

显而易见的问题似乎是,您确定您的谓词与您保存的任何对象匹配吗?您的 recordCount 方法不使用谓词,但您的 fetched results 控制器使用,因此如果没有与谓词匹配,则不会找到任何内容。 @TomHarrington 感谢您的阅读。我的第一个想法也是谓词的问题。我已经将工作代码从 Swift 2 项目复制到了这个项目(将语法更新到 Swift 3)并且我在 Swift 3 项目的托管对象上保持了相同的属性名称,这让我觉得我遇到了配置问题FRC。 是的,但是您是否知道一些数据可以让您确定某些对象与谓词匹配?如果没有匹配项,则等效代码无关紧要。 【参考方案1】:

您的 NSFetchRequest 应该有一个类型 NSFetchRequest&lt;MyEntity&gt;,但您指定了 NSFetchRequest&lt;NSFetchRequestResult&gt;。尝试更改此设置并告诉我是否有帮助

【讨论】:

【参考方案2】:

请查看下面的 NSFetchedResultsController swift 3 代码..

 override func viewDidLoad() 
     super.viewDidLoad()
    do 
        try self.fetchedResultsController.performFetch()
     catch 
        let fetchError = error as NSError
        print("Unable to Perform Fetch Request")
        print("\(fetchError), \(fetchError.localizedDescription)")
    

// MARK: - NSFetchedResultsController

fileprivate lazy var fetchedResultsController: NSFetchedResultsController<UserExistenceOnXMPPCD> = 
    let fetchRequest = NSFetchRequest<UserExistenceOnXMPPCD>(entityName: "UserExistenceOnXMPPCD")
    fetchRequest.sortDescriptors = [
        NSSortDescriptor(key: "name", ascending: true)]

    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext:CoreDataController.sharedInstance.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

    try! fetchedResultsController.performFetch()
    fetchedResultsController.delegate = self
    if let quotes = fetchedResultsController.fetchedObjects 
        if quotes.count > 0 
            print(quotes.count)
        
    
    return fetchedResultsController
()


// MARK: - NSFetchedResultsController delegate methods
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)  
    tableView.beginUpdates()


func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)  
    tableView.reloadData()

【讨论】:

以上是关于在 Swift 3 中难以配置 NSFetchedResultsController的主要内容,如果未能解决你的问题,请参考以下文章

Swift 协议扩展中的“关联类型”难以理解

Swift:如何附加到 NSObject 数组?

无法使用 Xcode 8 和 Swift 3 在 SpriteKit 中以编程方式触发 segue

隔离 View 和 Model (Swift)

Swift 中 Vision/CoreML 对象识别器的精度

Firebase Swift 3 使用 NSURLSession 将配置文件图像加载到 TableView