Утечка памяти при использовании CombineLatest в Swift Combine - PullRequest
0 голосов
/ 19 апреля 2020

Я использую шаблон 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
}

1 Ответ

0 голосов
/ 19 апреля 2020

$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] }
...