Skip to content

[FR] Is FIRConfigUpdateListenerRegistration thread-safe? If not, can it be made thread-safe and Sendable? #14215

Closed
@ehyche

Description

@ehyche

Description

I am creating an extension on RemoteConfig to provide an AsyncStream API on top of addOnConfigUpdateListener():

extension RemoteConfig {

    public static func onConfigUpdateThrowingStream() -> AsyncThrowingStream<Set<String>, any Error> {
        AsyncThrowingStream { continuation in
            let registration = RemoteConfig.remoteConfig().addOnConfigUpdateListener { update, error in
                if let error {
                    continuation.finish(throwing: error)
                } else if let update {
                    continuation.yield(update.updatedKeys)
                }
            }
            let registrationSendable = ConfigUpdateListenerRegistrationSendable(registration: registration)
            continuation.onTermination = { _ in
                registrationSendable.registration.remove()
            }
        }
    }
}

struct ConfigUpdateListenerRegistrationSendable: @unchecked Sendable {
    let registration: ConfigUpdateListenerRegistration
}

As you can see, since ConfigUpdateListenerRegistration is not Sendable, then I am wrapping it in an @unchecked Sendable struct.

From looking at the code, this appears to be safe to me, since in the implementation of the ConfigUpdateListenerRegistration.remove() method:

- (void)remove {
  [self->_realtimeClient removeConfigUpdateListener:_completionHandler];
}

which in turn does an operation on a serial queue:

- (void)removeConfigUpdateListener:(void (^_Nonnull)(FIRRemoteConfigUpdate *configUpdate,
                                                     NSError *_Nullable error))listener {
  __weak RCNConfigRealtime *weakSelf = self;
  dispatch_async(_realtimeLockQueue, ^{
    __strong RCNConfigRealtime *strongSelf = weakSelf;
    [strongSelf->_listeners removeObject:listener];
    if (strongSelf->_listeners.count == 0) {
      [strongSelf pauseRealtimeStream];
    }
  });
}

So it appears to me that ConfigUpdateListenerRegistration should be thread-safe. If so, can we please mark the type as Sendable so that I don't have to do this @unchecked Sendablewrapper to avoid the Swift 6 errors?

API Proposal

Just mark the ConfigUpdateListenerRegistration type as Sendable.

Firebase Product(s)

Remote Config

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions