如何使用组合来分配从核心数据获取请求返回的元素数量?

Posted

技术标签:

【中文标题】如何使用组合来分配从核心数据获取请求返回的元素数量?【英文标题】:How to use Combine to assign the number of elements returned from a Core Data fetch request? 【发布时间】:2019-09-03 06:43:09 【问题描述】:

我希望我的应用定期获取新记录并将它们存储在 Core Data 中。我的 UI 上有一个标签,应该显示特定记录的元素数量,并且我希望随着更多记录添加到数据库中来更新该数字。作为一个练习,我想使用 Combine 来完成它。

当应用程序启动时,我能够显示数据库中元素的数量,但是当新数据进入数据库时​​,数字不会更新(我通过实现一个按钮验证了新数据正在添加会手动刷新 UI)。

这是在启动时显示正确数量的元素但在添加新记录时不更新的代码:

let replayRecordFetchRequest: NSFetchRequest<ReplayRecord> = ReplayRecord.fetchRequest()

_ = try? persistentContainer.viewContext.fetch(replayRecordFetchRequest).publisher.count().map  String(format: Constants.Strings.playsText, $0) .assign(to: \.text, on: self.playsLabel)

这是我改编的 WWDC 2019 Session 230 演讲中的代码 sn-p,但这根本不起作用(订阅者永远不会被解雇):

let replayRecordFetchRequest: NSFetchRequest<ReplayRecord> = ReplayRecord.fetchRequest()

if let replayRecords = try? replayRecordFetchRequest.execute() 
    _ = replayRecords.publisher.count().map  String(format: Constants.Strings.playsText, $0) .assign(to: \.text, on: self.playsLabel)

【问题讨论】:

【参考方案1】:

所以,我直到现在才知道这一点,但并非所有出版商都无限活跃。

问题是NSFetchRequest.publisher 不是一个长期存在的发布者。它只是提供了一种方法来遍历获取请求中的元素序列。结果,订阅者将在元素迭代后取消。在我的例子中,我计算了在取消之前发布的元素,然后将该值分配给 UI。

相反,我应该订阅对托管对象上下文的更改并将该管道分配给我的 UI。下面是一些示例代码:

extension NotificationCenter.Publisher 
    func context<T>(fetchRequest: NSFetchRequest<T>) -> Publishers.CompactMap<NotificationCenter.Publisher, [T]> 
        return compactMap  notification -> [T]? in
            let context = notification.object as! NSManagedObjectContext
            var results: [T]?
            context.performAndWait 
                results = try? context.fetch(fetchRequest)
            
            return results
        
    


let playFetchRequest: NSFetchRequest<ReplayRecord> = ReplayRecord.fetchRequest()
let replayVideoFetchRequest: NSFetchRequest<ReplayVideo> = ReplayVideo.fetchRequest()

let playsPublisher = contextDidSavePublisher.context(fetchRequest: playFetchRequest).map(\.count)
let replayVideoPublisher = contextDidSavePublisher.context(fetchRequest: replayVideoFetchRequest).map(\.count)

playsSubscription = playsPublisher.zip(replayVideoPublisher).map 
    String(format: Constants.Strings.playsText, $0, $1)

.receive(on: RunLoop.main).assign(to: \.text, on: self.playsLabel)

【讨论】:

fetch 返回一个记录数组,所以你得到一个数组发布者

以上是关于如何使用组合来分配从核心数据获取请求返回的元素数量?的主要内容,如果未能解决你的问题,请参考以下文章

从核心数据获取请求中排除反向关系

核心数据获取请求不返回不同的结果

---数组和指针的常见用法

从 n 返回 k 个元素的连续组合的按需算法

如何从 FMDB 获取两个数据并快速返回一个将其中两个组合在一起的字符串?

在python中使用递归来组合可变大小的列表