Showing you my code:
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)
// 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<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 // 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: &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<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)
}
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.
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.