我真的很困惑,为什么这个出版商是不解雇,我会非常感谢有人有经验的阐明这里发生了什么。
我正在尝试构建一个服务,它公开了一个合并接口,用于访问Core Data中的一些数据。
我有下面的代码,这应该是一个相对完整的例子来演示我的问题(你必须做一些额外的设置来编译,但如果你熟悉CD和UIKit,你应该没有问题):
/// 1. Core Data Stack
import CoreData
struct CoreDataStack {
let container: NSPersistentCloudKitContainer
init(
name: String = "TasksPrototype",
inMemory: Bool = false
) {
container = NSPersistentCloudKitContainer(name: name)
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
}
}
/// 2. Task Data Models (CoreData + UI model)
@objc(TaskEntity)
public class TaskEntity: NSManagedObject {
}
extension TaskEntity {
@nonobjc public class func fetchRequest() -> NSFetchRequest<TaskEntity> {
return NSFetchRequest<TaskEntity>(entityName: "TaskEntity")
}
@NSManaged public var id: UUID?
@NSManaged public var title: String?
@NSManaged public var creationDate: Date?
}
extension TaskEntity : Identifiable {
}
struct Task: Equatable {
var id: UUID
var creationDate: Date
var title: String
init(
id: UUID = UUID(),
creationDate: Date = Date(),
title: String = "Untitled"
) {
self.id = id
self.creationDate = creationDate
self.title = title
}
init?(
entity: TaskEntity
) {
guard let id = entity.id,
let creationDate = entity.creationDate,
let title = entity.title else { fatalError() }
self.id = id
self.creationDate = creationDate
self.title = title
}
}
/// 3. Service
struct TaskService {
private let coreDataStack: CoreDataStack
let monitorPublisher: ManagedObjectChangesPublisher<TaskEntity>
init(
coreDataStack: CoreDataStack
) {
self.coreDataStack = coreDataStack
let req = TaskEntity.fetchRequest()
req.sortDescriptors = []
self.monitorPublisher = coreDataStack.container.viewContext.changesPublisher(for: req)
}
func monitor() -> AnyPublisher<[Task], Error> {
return monitorPublisher
.reduce([]) { (accum: [TaskEntity], diff: CollectionDifference<TaskEntity>) -> [TaskEntity] in
return accum.applying(diff) ?? []
}
.compactMap { $0.compactMap(Task.init(entity:)) }
.eraseToAnyPublisher()
}
/// 4. ManagedObjectChangesPublisher
/// See https://gist.githubusercontent.com/andreyz/757ec98b5e567cddd5ff55e1fd2c1e19/raw/c2e4638861bb39b77dcca72a29f29a3c2bacc559/ManagedObjectChangesPublisher.swift
/// 5. View Controller
class ViewController: UIViewController {
private let taskService = TaskService(coreDataStack: CoreDataStack())
private var cancellables: [AnyCancellable] = []
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
taskService.monitor()
.sink(receiveCompletion: { _ in }) { tasks in
print(tasks)
}.store(in: &cancellables)
}
}
我可以在TaskService
中设置一个断点,然后看到我的reduce被调用,但之后没有任何操作被调用,在我的VC中,没有调用接收器。
这不是没有项的问题,因为即使我从TaskService返回一些虚拟项,我也没有在ViewController
中执行任何工作。
订阅这个出版商似乎出了点问题,但我不知道是什么。
提前感谢任何帮助。
我已经尝试设置print()
调试操作,设置断点,但我仍然不知道为什么发布服务器不启动。
1条答案
按热度按时间ymzxtsji1#
我终于明白为什么我的出版商从来不解雇我了。
我使用的是
reduce
操作符,当上游发布者完成时,according to the documentation将生成一个值。在这种情况下,上游发布者永远不会完成,因为它是一个通知发布者。我实际需要的操作符是
scan
--它在接收到每个累积值时传递它,而不等待上游发布者完成。