I am using the Redux pattern for building a messaging application. Everything works fine so far but then I notice a memory leak in some parts of the app that I'm unable to solve. My view controller that binds to messages publisher. Deinit won't get called when the view controller is dismissed.
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)
When I changed from referencing a dictionary object to another object in the chat state deinit
gets called
let chatRoomDetailResponse = {
store.$state
.map { $0.chatState.getChatRoomDetailResponse }
.removeDuplicates()
.eraseToAnyPublisher()
}()
chatRoomDetailResponse.combineLatest(Just("Hello world"))
.sink { [weak self] (messages, state) in
}
.store(in: &cancellableSet)
This is a small snapshot of my store:
final public class Store<State: FluxState>: ObservableObject {
@Published public var state: State
private var dispatchFunction: DispatchFunction!
private let reducer: Reducer<State>
and my ChatState:
public struct ChatState: FluxState {
public typealias ChannelID = String
public var messagesByChannel: [ChannelID: [Message]] = [:]
public var getChatRoomDetailResponse: NetworkResponse<ChatChannel>? = nil
}
$0.chatState.messagesByChannel[self.channelId]
is capturing self
strongly, for the sake of being able to access its most-up-to-date channelId
value.
Either catpure self weakly:
.map { [weak self] in
guard let strongSelf = self else { return ??? }
$0.chatState.messagesByChannel[strongSelf.channelId]
}
Or if channelId
doesn't change, you can use a capture list to capture it by value:
.map { [channelId] in $0.chatState.messagesByChannel[channelId] }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.