如何在 cellEdit 之后强制从持久存储重新加载核心数据

Posted

技术标签:

【中文标题】如何在 cellEdit 之后强制从持久存储重新加载核心数据【英文标题】:how to force core data reload from persistent storage after cellEdit 【发布时间】:2016-12-06 04:25:10 【问题描述】:

编辑单元格后,我无法从核心数据持久存储重新加载数据。

我尝试重新加载 tableView 本身,但这不会强制从持久存储中获取,我该如何强制重新加载?

这是我重新加载的尝试,但如果我退出 UIViewController 并返回所有工作,那么我知道持久存储已正确更新

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath


    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];

    NSManagedObjectContext *context = appDelegate.persistentContainer.viewContext;

    if([NWTillHelper isDebug] == 1) 
        NSLog(@"TransactionListView:tableView:context = %@", context);
    

    if (editingStyle == UITableViewCellEditingStyleDelete) 

        NSManagedObject *transactionRow = [self.transactionRowsRows objectAtIndex:indexPath.row];

        [transactionRow setValue:[NSNumber numberWithInt:[@"999" intValue]] forKey:@"status"];
        [transactionRow setValue:[NSNumber numberWithInt:[@"0" intValue]] forKey:@"qty"];
        [transactionRow setValue:[NSDecimalNumber decimalNumberWithString:@"0"] forKey:@"price"];
        [transactionRow setValue:[NSDecimalNumber decimalNumberWithString:@"0"] forKey:@"discountPercentage"];
        [transactionRow setValue:[NSDecimalNumber decimalNumberWithString:@"0"] forKey:@"discountAmount"];
        [transactionRow setValue:[NSDecimalNumber decimalNumberWithString:@"0"] forKey:@"amountTax"];
        [transactionRow setValue:[NSDecimalNumber decimalNumberWithString:@"0"] forKey:@"sum"];

        NSError *error = nil;
        if (![context save:&error]) 
            if([NWTillHelper isDebug] == 1) 
                NSLog(@"Can't Delete! %@ %@", error, [error localizedDescription]);
                return;
            
        
        [self.transactionListViewTbl reloadData];
    

【问题讨论】:

【参考方案1】:

只是想提一下。

阅读您的问题后,我觉得它不会使用 Fetch Controller 来修复。 Fetch Controller 非常简洁,它可以让您保持表格更新,而无需显式调用 [table reloadData]。但是,如果重新加载您的表数据没有得到更新,您可能有多个托管对象上下文更新您的持久存储。

数据由不同的托管对象上下文更新,并且您没有在连接表的那个上下文中获得更新。我将从查看我的核心数据堆栈和托管对象上下文的数量开始。如果您需要超过 1 个,您可以订阅更改,或者确保您希望看到的更改是在同一个托管对象上下文中完成的。

希望对你有帮助。

Managed Object Context - Apple Docs

【讨论】:

我在每个方法中都有一个托管对象上下文,但在同一个方法中我只有一个,它会在方法之间发生冲突吗?如果是这样,我怎样才能制作一个在所有方法中都持久的? 谢谢,我有两个上下文竞争我是一个复制和粘贴错误,我认为很多深夜编码,感谢您对此的提醒。【参考方案2】:

使用 NSFetchedResultsController 作为数据源并实现 NSFecthedResultsController 委托

您可以在 viewController 中创建 NSFetchedResults 控制器作为属性,创建它的单个实例

lazy var transactionFetchedResultsController : NSFetchedResultsController<Transaction> = 
        let appdelegate = UIApplication.shared.delegate as! AppDelegate
        var fetchedResultsController : NSFetchedResultsController< Transaction >!

        appdelegate.managedObjectContext.performAndWait 
            var fetchRequest: NSFetchRequest< Transaction >
            if #available(ios 10.0, *) 
                fetchRequest = Transaction.fetchRequest()
             else 
                fetchRequest  = NSFetchRequest(entityName: "Transaction")
            

            fetchRequest.sortDescriptors = [NSSortDescriptor(key: "your_property", ascending: true)]
            let yourPredicate = NSPredicate(format: "your condition == whatever")
            fetchRequest.predicate = yourPredicate
            fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: appdelegate.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
        
        return fetchedResultsController
    ()

为您的 viewController 设置委托

self. transactionFetchedResultsController.delegate = self

最后在viewDidLoad()中初始化

try! self. transactionFetchedResultsController.performFetch()

现在实现委托:)

extension YourViewController : NSFetchedResultsControllerDelegate
    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) 
        //row updated
    

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) 
        //section updated
    

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
        //change completed
        //reload your tableView
    

编辑

如果您想知道如何使用 NSFetchedResultsController 作为 tableView 数据源?

extension YourViewController: UITableViewDataSource 
    func numberOfSections(in tableView: UITableView) -> Int 
        return (self. transactionFetchedResultsController.sections?.count)!
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
           //assuming you have only one section
           //you can always return number of items in each section using NSFetchedResultsController :)
            return (self. transactionFetchedResultsController.fetchedObjects?.count)!
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        //let cell = ....
        //you can instantiate your cell here
        //you can access your transaction as below
        let transaction = self. transactionFetchedResultsController.fetchedObjects![indexPath.row]
        //return your cell
        return cell
    

希望对你有帮助:)

【讨论】:

这看起来不错,我正在尝试翻译成 ObjC @matt-douhan : 抱歉,哥们没有客观的 C 代码示例,从现在开始就停止了它的工作:( @matt-douhan : Bingo :) 请考虑接受答案,以防它有效并帮助你:)

以上是关于如何在 cellEdit 之后强制从持久存储重新加载核心数据的主要内容,如果未能解决你的问题,请参考以下文章

如何强制重新获取 NSManagedObject 的关系集

如何强制 Django 忽略任何缓存并重新加载数据?

CKEditor插件在删除后缓存在磁盘中。如何强制浏览器重新扫描或删除该缓存?

在 cellEditable 材质表上,如何限制用户输入负数?

如何在 Windows 上的多个进程上存储持久设置

iOS数据存储之属性列表理解