将CurrentValueSubject中的值包装在一个AnyPublisher中,并传递给另一个类。

huangapple go评论71阅读模式
英文:

Pass CurrentValueSubject value wrapped in an AnyPublisher to another class

问题

以下是您的代码的翻译部分:

protocol SomeProtocol {
    var isLocalNotificationsEnabledPublisher: AnyPublisher<Bool, Error> { get }
    
    func saveLocalNotifications(_ enabled: Bool) throws
}

final class UserSettingsClass {
    private var repository: CoreDataRepo
    
    private var isLocalNotificationsEnabledSubject = CurrentValueSubject<Bool, Error>(false) 
    // 我将其设置为私有,以防其他类从外部更改它,我只能订阅它的值。
    
    private var cancellables = Set<AnyCancellable>()
    
    init(repository: CoreDataRepo) {
        self.repository = repository
        binding()
    }
}

extension UserSettingsClass: SomeProtocol {
    var isLocalNotificationsEnabledPublisher: AnyPublisher<Bool, Error> {
        return isLocalNotificationsEnabledSubject.eraseToAnyPublisher()
    }

    func saveLocalNotifications(_ enabled: Bool) throws {
        var userSettings = userSettings // 这是核心数据对象... 
        
        userSettings?.isLocalNotificationsEnabled = enabled 
        // 这是重要部分,它具有此切换。
        // 我需要能够将这个值发送到我的LocalNotificaitonsService类,并基于这个值判断是否可以发送本地通知。
        
        if isLocalNotificationsEnabledSubject.value != enabled {
            throw someError
        }
        
        isLocalNotificationsEnabledSubject.send(userSettings?.isLocalNotificationsEnabled ?? false)
    }
}

以下是如何将其绑定到发布者以便我可以订阅saveLocalNotifications方法中发送的值的方式:

private func binding() {
        isLocalNotificationsEnabledPublisher
            .sink(
                receiveCompletion: { _ in },
                receiveValue: { [weak self] value in
                    do {
                        try saveLocalNotifications(value) // 这里有递归 + 未正确处理错误...
                    } catch {
                        return
                    }
                }
                
            ).store(in: &cancellables)
    }

这段代码导致了导致我的应用程序崩溃的递归。以下是我尝试在本地通知管理器中使用它的方式:

private let isLocalNotificationsEnabledPublisher: AnyPublisher<Bool, Error>
    
private var cancellables = Set<AnyCancellable>()
    
public init(isLocalNotificationsEnabledPublisher: AnyPublisher<Bool, Error>) {
        self.isLocalNotificationsEnabledPublisher = isLocalNotificationsEnabledPublisher
    }
extension LocalNotificationsManager: SomeOtherProtocol {
    public func requestNotificationAuthorization() throws {
        isLocalNotificationsEnabledPublisher
            .sink(
                receiveCompletion: { _ in },
                receiveValue: { [weak self] value in
                    if value == true {
                        Task {
                            try await self?.center.requestAuthorization(options: [.badge, .sound, .alert])
                        }
                    }
                }
            ).store(in: &cancellables)
    }
}

因此,这段代码不起作用,因为我不知道如何在本地通知管理器类中获取主题值。我需要能够订阅用户设置中的切换值,并决定是否可以发送本地通知。感谢您提前的帮助。

英文:

Showing you my code:

protocol SomeProtocol {
    var isLocalNotificationsEnabledPublisher: AnyPublisher&lt;Bool, Error&gt; { get }
    
    func saveLocalNotifications(_ enabled: Bool) throws
}

final class UserSettingsClass {
    private var repository: CoreDataRepo
    
    private var isLocalNotificationsEnabledSubject = CurrentValueSubject&lt;Bool, Error&gt;(false) 
// I make it private so that no other classes can change it from outside,
// I can only subscribe on its values.
    
    private var cancellables = Set&lt;AnyCancellable&gt;()
    
    init(repository: CoreDataRepo) {
        self.repository = repository
        binding()
    }
}

extension UserSettingsClass: SomeProtocol {
    var isLocalNotificationsEnabledPublisher: AnyPublisher&lt;Bool, Error&gt; {
        return isLocalNotificationsEnabledSubject.eraseToAnyPublisher()
    }

    func saveLocalNotifications(_ enabled: Bool) throws {
        var userSettings = userSettings // this is core data object... 
        
        userSettings?.isLocalNotificationsEnabled = enabled 
// this is the important part, it has this toggle.
// I need to be able to send this value to my LocalNotificaitonsService class and based
// on this value understand whether I can send local notifications or not.
        
        if isLocalNotificationsEnabledSubject.value != enabled {
            throw someError
        }
        
        isLocalNotificationsEnabledSubject.send(userSettings?.isLocalNotificationsEnabled ?? false)
    }
}

Here is how I bind it to my publisher so that I could subscribe to the value that I send in the saveLocalNotifications method:

private func binding() {
        isLocalNotificationsEnabledPublisher
            .sink(
                receiveCompletion: { _ in },
                receiveValue: { [weak self] value in
                    do {
                        try saveLocalNotifications(value) // recursion here + not handling error properly...
                    } catch {
                        return
                    }
                }
                
            ).store(in: &amp;cancellables)
    }

This code causes recursion that leads to my app crashing.
Here is how I try to use it in my local notifications manager:

private let isLocalNotificationsEnabledPublisher: AnyPublisher&lt;Bool, Error&gt;
    
private var cancellables = Set&lt;AnyCancellable&gt;()
    
public init(isLocalNotificationsEnabledPublisher: AnyPublisher&lt;Bool, Error&gt;) {
        self.isLocalNotificationsEnabledPublisher = isLocalNotificationsEnabledPublisher
    }
extension LocalNotificationsManager: SomeOtherProtocol {
    public func requestNotificationAuthorization() throws {
        isLocalNotificationsEnabledPublisher
            .sink(
                receiveCompletion: { _ in },
                receiveValue: { [weak self] value in
                    if value == true {
                        Task {
                            try await self?.center.requestAuthorization(options: [.badge, .sound, .alert])
                        }
                    }
                }
            ).store(in: &amp;cancellables)
    }

So basically this code does not work properly because I do not understand how to get the subject value in the local notifications manager class. I need to be able to sink on the toggle value from the user settings and decide if I can or can not send local notifications.
Thank you in advance.

答案1

得分: 1

你出现递归是因为你调用了saveLocalNotifications,然后触发了Combine链,因为它反过来调用了isLocalNotificationsEnabledSubject.send(...)

为了防止递归,你可以在订阅isLocalNotificationsEnabledSubject的Combine链中使用removeDuplicates

话虽如此,你可能需要重新考虑你的架构,以避免递归的发生。

英文:

You have recursion because you call saveLocalNotifications and then that triggers the Combine chain again, since that in turn calls isLocalNotificationsEnabledSubject.send(...).

To prevent the recursion, you could use removeDuplicates in the Combine chain where you subscribe to isLocalNotificationsEnabledSubject

That being said, you may wan to reconsider your architecture so that the recursion isn't possible.

huangapple
  • 本文由 发表于 2023年6月5日 03:52:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76402162.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定