Утечка памяти при использовании CombineLatest в Swift Combine

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

        let messages = {
            store.$state
                .map { $0.chatState.messagesByChannel[self.channelId] }
                .removeDuplicates()
                .eraseToAnyPublisher()
        }()

        messages.combineLatest(Just("Hello world"))
            .sink { [weak self] (messages, state) in

        }
        .store(in: &cancellableSet)

Когда я перешел со ссылки на объект словаря на другой объект в состоянии чата, вызывается deinit

        let chatRoomDetailResponse = {
            store.$state
            .map { $0.chatState.getChatRoomDetailResponse }
                .removeDuplicates()
                .eraseToAnyPublisher()
        }()

        chatRoomDetailResponse.combineLatest(Just("Hello world"))
            .sink { [weak self] (messages, state) in

        }
        .store(in: &cancellableSet)

Это небольшой снимок моего магазина:

final public class Store<State: FluxState>: ObservableObject {
    @Published public var state: State

    private var dispatchFunction: DispatchFunction!
    private let reducer: Reducer<State>

и мой ChatState:


public struct ChatState: FluxState {

    public typealias ChannelID = String

    public var messagesByChannel: [ChannelID: [Message]] = [:]

    public var getChatRoomDetailResponse: NetworkResponse<ChatChannel>? = nil
}

person kelvinleeweisern    schedule 19.04.2020    source источник


Ответы (1)


$0.chatState.messagesByChannel[self.channelId] сильно захватывает self, чтобы иметь возможность получить доступ к самому актуальному channelId значению.

Либо убивает себя слабо:

.map { [weak self] in 
    guard let strongSelf = self else  { return ??? }
    $0.chatState.messagesByChannel[strongSelf.channelId]
}

Или, если channelId не меняется, вы можете использовать список захвата, чтобы захватить его по значению:

.map { [channelId] in $0.chatState.messagesByChannel[channelId] }
person Alexander    schedule 19.04.2020