为什么Swift Publisher从来不火?

lmvvr0a8  于 2023-06-28  发布在  Swift
关注(0)|答案(1)|浏览(120)

我真的很困惑,为什么这个出版商是不解雇,我会非常感谢有人有经验的阐明这里发生了什么。
我正在尝试构建一个服务,它公开了一个合并接口,用于访问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()调试操作,设置断点,但我仍然不知道为什么发布服务器不启动。

ymzxtsji

ymzxtsji1#

我终于明白为什么我的出版商从来不解雇我了。
我使用的是reduce操作符,当上游发布者完成时,according to the documentation将生成一个值。
在这种情况下,上游发布者永远不会完成,因为它是一个通知发布者。我实际需要的操作符是scan--它在接收到每个累积值时传递它,而不等待上游发布者完成。

相关问题