From 825444d92fa1b7ea1077b694aa76d9610c7347ae Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Fri, 29 Oct 2021 16:34:51 +0300 Subject: [PATCH] Fixes vector-im/element-ios/issues/5063 - Fixed retain cycles between the user suggestion coordinator and the suggestion service, and in the suggestion service currentTextTrigger subject sink. --- .../UserSuggestionCoordinator.swift | 31 ++++++++++++------- .../Mock/MockUserSuggestionScreenState.swift | 2 +- .../Service/UserSuggestionService.swift | 10 +++--- changelog.d/5063.bugfix | 1 + 4 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 changelog.d/5063.bugfix diff --git a/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift b/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift index bc50aae42c..e7308710d5 100644 --- a/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift @@ -34,11 +34,10 @@ final class UserSuggestionCoordinator: Coordinator { private let parameters: UserSuggestionCoordinatorParameters - private var userSuggestionHostingController: UIViewController! - private var userSuggestionService: UserSuggestionServiceProtocol! - private var userSuggestionViewModel: UserSuggestionViewModelProtocol! - - private var roomMembers: [MXRoomMember] = [] + private var userSuggestionHostingController: UIViewController + private var userSuggestionService: UserSuggestionServiceProtocol + private var userSuggestionViewModel: UserSuggestionViewModelProtocol + private var roomMemberProvider: UserSuggestionCoordinatorRoomMemberProvider // MARK: Public @@ -54,9 +53,10 @@ final class UserSuggestionCoordinator: Coordinator { init(parameters: UserSuggestionCoordinatorParameters) { self.parameters = parameters - userSuggestionService = UserSuggestionService(roomMembersProvider: self) + roomMemberProvider = UserSuggestionCoordinatorRoomMemberProvider(room: parameters.room) + userSuggestionService = UserSuggestionService(roomMemberProvider: roomMemberProvider) userSuggestionViewModel = UserSuggestionViewModel.makeUserSuggestionViewModel(userSuggestionService: userSuggestionService) - + let view = UserSuggestionList(viewModel: userSuggestionViewModel.context) .addDependency(AvatarService.instantiate(mediaManager: parameters.mediaManager)) @@ -69,7 +69,7 @@ final class UserSuggestionCoordinator: Coordinator { switch result { case .selectedItemWithIdentifier(let identifier): - guard let member = self.roomMembers.filter({ $0.userId == identifier }).first else { + guard let member = self.roomMemberProvider.roomMembers.filter({ $0.userId == identifier }).first else { return } @@ -93,9 +93,18 @@ final class UserSuggestionCoordinator: Coordinator { } @available(iOS 14.0, *) -extension UserSuggestionCoordinator: RoomMembersProviderProtocol { +private class UserSuggestionCoordinatorRoomMemberProvider: RoomMembersProviderProtocol { + + private let room: MXRoom + + var roomMembers: [MXRoomMember] = [] + + init(room: MXRoom) { + self.room = room; + } + func fetchMembers(_ members: @escaping ([RoomMembersProviderMember]) -> Void) { - parameters.room.members({ [weak self] roomMembers in + room.members({ [weak self] roomMembers in guard let self = self, let joinedMembers = roomMembers?.joinedMembers else { return } @@ -108,7 +117,7 @@ extension UserSuggestionCoordinator: RoomMembersProviderProtocol { self.roomMembers = joinedMembers members(self.roomMembersToProviderMembers(joinedMembers)) }, failure: { error in - MXLog.error("[UserSuggestionCoordinator] Failed loading room with error: \(String(describing: error))") + MXLog.error("[UserSuggestionCoordinatorRoomMemberProvider] Failed loading room with error: \(String(describing: error))") }) } diff --git a/RiotSwiftUI/Modules/Room/UserSuggestion/Service/Mock/MockUserSuggestionScreenState.swift b/RiotSwiftUI/Modules/Room/UserSuggestion/Service/Mock/MockUserSuggestionScreenState.swift index 7897c608dc..7d4180201f 100644 --- a/RiotSwiftUI/Modules/Room/UserSuggestion/Service/Mock/MockUserSuggestionScreenState.swift +++ b/RiotSwiftUI/Modules/Room/UserSuggestion/Service/Mock/MockUserSuggestionScreenState.swift @@ -30,7 +30,7 @@ enum MockUserSuggestionScreenState: MockScreenState, CaseIterable { } var screenView: ([Any], AnyView) { - let service = UserSuggestionService(roomMembersProvider: self) + let service = UserSuggestionService(roomMemberProvider: self) let listViewModel = UserSuggestionViewModel.makeUserSuggestionViewModel(userSuggestionService: service) let viewModel = UserSuggestionListWithInputViewModel(listViewModel: listViewModel) { textMessage in diff --git a/RiotSwiftUI/Modules/Room/UserSuggestion/Service/UserSuggestionService.swift b/RiotSwiftUI/Modules/Room/UserSuggestion/Service/UserSuggestionService.swift index ad9de7e569..6e4fab347c 100644 --- a/RiotSwiftUI/Modules/Room/UserSuggestion/Service/UserSuggestionService.swift +++ b/RiotSwiftUI/Modules/Room/UserSuggestion/Service/UserSuggestionService.swift @@ -45,7 +45,7 @@ class UserSuggestionService: UserSuggestionServiceProtocol { // MARK: Private - private let roomMembersProvider: RoomMembersProviderProtocol + private let roomMemberProvider: RoomMembersProviderProtocol private var suggestionItems: [UserSuggestionItemProtocol] = [] private let currentTextTriggerSubject = CurrentValueSubject(nil) @@ -61,13 +61,13 @@ class UserSuggestionService: UserSuggestionServiceProtocol { // MARK: - Setup - init(roomMembersProvider: RoomMembersProviderProtocol) { - self.roomMembersProvider = roomMembersProvider + init(roomMemberProvider: RoomMembersProviderProtocol) { + self.roomMemberProvider = roomMemberProvider currentTextTriggerSubject .debounce(for: 0.5, scheduler: RunLoop.main) .removeDuplicates() - .sink { self.fetchAndFilterMembersForTextTrigger($0) } + .sink { [weak self] in self?.fetchAndFilterMembersForTextTrigger($0) } .store(in: &cancellables) } @@ -96,7 +96,7 @@ class UserSuggestionService: UserSuggestionServiceProtocol { partialName.removeFirst() // remove the '@' prefix - roomMembersProvider.fetchMembers { [weak self] members in + roomMemberProvider.fetchMembers { [weak self] members in guard let self = self else { return } diff --git a/changelog.d/5063.bugfix b/changelog.d/5063.bugfix new file mode 100644 index 0000000000..d1ee811c17 --- /dev/null +++ b/changelog.d/5063.bugfix @@ -0,0 +1 @@ +Fixed retain cycles between the user suggestion coordinator and the suggestion service, and in the suggestion service currentTextTrigger subject sink. \ No newline at end of file