Что лучше при создании нескольких издателей в Combine? AnyCancellable для каждого или Set <AnyCancellable>с .store (в: & self.cancellableSet)? - PullRequest
0 голосов
/ 06 апреля 2020

Я немного новичок в Комбинировании и реактивном программировании в целом. Я думаю, что натолкнулся на два разных способа сделать то же самое, но мне интересно, почему я должен выбрать один из других.

У меня есть простая модель, которая хранит и публикует значения, связанные с Apple Смотреть статус. Ниже приведены два разных способа, которые, как мне кажется, я делаю одинаково.

В этом первом подходе я использую отдельный AnyCancellable? для каждого Publisher:

class WatchConnectivityModel: ObservableObject {

    init() {
        activationState = WCSession.default.activationState
        isWatchAppInstalled = WCSession.default.isWatchAppInstalled
        isComplicationEnabled = WCSession.default.isComplicationEnabled

        assignPublishers()
    }

    @Published var activationState: WCSessionActivationState
    @Published var isWatchAppInstalled: Bool
    @Published var isComplicationEnabled: Bool

    private var activationStateStream: AnyCancellable?
    private var isWatchAppInstalledStream: AnyCancellable?
    private var isComplicationEnabledStream: AnyCancellable?

    private func assignPublishers() {
        activationStateStream = WCSession.default
            .publisher(for: \.activationState)
            .receive(on: RunLoop.main)
            .assign(to: \.activationState, on: self)

        isWatchAppInstalledStream = WCSession.default
            .publisher(for: \.isWatchAppInstalled)
            .receive(on: RunLoop.main)
            .assign(to: \.isWatchAppInstalled, on: self)

        isComplicationEnabledStream = WCSession.default
            .publisher(for: \.isComplicationEnabled)
            .receive(on: RunLoop.main)
            .assign(to: \.isComplicationEnabled, on: self)
    }
}

Вот мой второй подход, но вместо отдельных AnyCancellable? объектов я использую один Set<AnyCancellable> вместе с .store(in: &self.cancellableSet) на каждом Publisher:

class WatchConnectivityModel: ObservableObject {

    init() {
        activationState = WCSession.default.activationState
        isWatchAppInstalled = WCSession.default.isWatchAppInstalled
        isComplicationEnabled = WCSession.default.isComplicationEnabled

        assignPublishers()
    }

    @Published var activationState: WCSessionActivationState
    @Published var isWatchAppInstalled: Bool
    @Published var isComplicationEnabled: Bool

    private var cancellableSet: Set<AnyCancellable> = []

    private func assignPublishers() {
        _ = WCSession.default
            .publisher(for: \.activationState)
            .receive(on: RunLoop.main)
            .assign(to: \.activationState, on: self)
            .store(in: &self.cancellableSet)

        _ = WCSession.default
            .publisher(for: \.isWatchAppInstalled)
            .receive(on: RunLoop.main)
            .assign(to: \.isWatchAppInstalled, on: self)
            .store(in: &self.cancellableSet)

        _ = WCSession.default
            .publisher(for: \.isComplicationEnabled)
            .receive(on: RunLoop.main)
            .assign(to: \.isComplicationEnabled, on: self)
            .store(in: &self.cancellableSet)
    }
}

Я предполагаю, что Первый подход был бы лучше, если бы мне нужно было что-то вручную сделать с одним из трех указанных c потоков, однако в этом случае мне это не нужно. Кроме этого, есть ли что-то, что делает один из этих подходов лучшим выбором, чем другой? Есть ли что-то важное, что я упускаю, когда дело доходит до управления памятью, когда одно происходит поверх другого?

Второе мне кажется немного странным из-за всей части _ =, потому что это похоже на дополнительный артефакт, который трудно объяснить: почему я все это приписываю ничему? Первый вариант позволяет избежать этой путаницы.

1 Ответ

1 голос
/ 06 апреля 2020

Нет особой причины создавать отдельную переменную для каждой подписки, если все подписки будут уничтожены одновременно.

Обратите внимание, что вам не нужно использовать Set<AnyCancellable>. Массив работает так же хорошо или лучше:

private var tickets: [AnyCancellable] = []

Вам не нужна «вся _ = часть» вообще. Метод store(in:) возвращает Void, поэтому компилятор знает, что возвращаемое значение можно игнорировать.

...