fix: status menu cause memory leaking issue

This commit is contained in:
CMK 2021-09-30 14:19:15 +08:00
parent c88daf56be
commit 80ea6ac913
12 changed files with 89 additions and 63 deletions

View File

@ -67,7 +67,6 @@ extension StatusSection {
timelineContext: TimelineContext,
dependency: NeedsDependency,
managedObjectContext: NSManagedObjectContext,
timestampUpdatePublisher: AnyPublisher<Date, Never>,
statusTableViewCellDelegate: StatusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate?,
threadReplyLoaderTableViewCellDelegate: ThreadReplyLoaderTableViewCellDelegate?
@ -363,7 +362,6 @@ extension StatusSection {
}
}()
if status.author.id == requestUserID || status.reblog?.author.id == requestUserID {
// do not filter myself
} else {
@ -473,9 +471,10 @@ extension StatusSection {
.receive(on: RunLoop.main)
.sink { _ in
// do nothing
} receiveValue: { [weak cell, weak tableView] change in
} receiveValue: { [weak cell, weak tableView, weak dependency] change in
guard let cell = cell else { return }
guard let tableView = tableView else { return }
guard let dependency = dependency else { return }
guard case .update(let object) = change.changeType,
let status = object as? Status, !status.isDeleted else {
return
@ -1107,7 +1106,7 @@ extension StatusSection {
StatusSection.setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status)
})
.store(in: &cell.disposeBag)
self.setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status)
setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status)
}
static func configureStatusAccessibilityLabel(cell: StatusTableViewCell) {

View File

@ -212,8 +212,17 @@ extension UserProviderFacade {
let name = mastodonUser.displayNameWithFallback
if let shareUser = shareUser {
let shareAction = UIAction(title: L10n.Common.Controls.Actions.shareUser(name), image: UIImage(systemName: "square.and.arrow.up"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in
let shareAction = UIAction(
title: L10n.Common.Controls.Actions.shareUser(name),
image: UIImage(systemName: "square.and.arrow.up"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .off
) { [weak provider, weak sourceView, weak barButtonItem] _ in
guard let provider = provider else { return }
guard let sourceView = sourceView else { return }
guard let barButtonItem = barButtonItem else { return }
let activityViewController = createActivityViewControllerForMastodonUser(mastodonUser: shareUser, dependency: provider)
provider.coordinator.present(
scene: .activityViewController(
@ -229,8 +238,17 @@ extension UserProviderFacade {
}
if let shareStatus = shareStatus {
let shareAction = UIAction(title: L10n.Common.Controls.Actions.sharePost, image: UIImage(systemName: "square.and.arrow.up"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in
let shareAction = UIAction(
title: L10n.Common.Controls.Actions.sharePost,
image: UIImage(systemName: "square.and.arrow.up"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .off
) { [weak provider, weak sourceView, weak barButtonItem] _ in
guard let provider = provider else { return }
guard let sourceView = sourceView else { return }
guard let barButtonItem = barButtonItem else { return }
let activityViewController = createActivityViewControllerForMastodonUser(status: shareStatus, dependency: provider)
provider.coordinator.present(
scene: .activityViewController(
@ -253,8 +271,9 @@ extension UserProviderFacade {
discoverabilityTitle: isMuting ? nil : L10n.Common.Controls.Friendship.muteUser(name),
attributes: isMuting ? [] : .destructive,
state: .off
) { [weak provider] _ in
) { [weak provider, weak cell] _ in
guard let provider = provider else { return }
guard let cell = cell else { return }
UserProviderFacade.toggleUserMuteRelationship(
provider: provider,
@ -283,8 +302,9 @@ extension UserProviderFacade {
discoverabilityTitle: isBlocking ? nil : L10n.Common.Controls.Friendship.blockUser(name),
attributes: isBlocking ? [] : .destructive,
state: .off
) { [weak provider] _ in
) { [weak provider, weak cell] _ in
guard let provider = provider else { return }
guard let cell = cell else { return }
UserProviderFacade.toggleUserBlockRelationship(
provider: provider,
@ -306,7 +326,14 @@ extension UserProviderFacade {
}
if !isMyself {
let reportAction = UIAction(title: L10n.Common.Controls.Actions.reportUser(name), image: UIImage(systemName: "flag"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in
let reportAction = UIAction(
title: L10n.Common.Controls.Actions.reportUser(name),
image: UIImage(systemName: "flag"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .off
) { [weak provider] _ in
guard let provider = provider else { return }
guard let authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else {
return
@ -328,19 +355,37 @@ extension UserProviderFacade {
if !isInSameDomain {
if isDomainBlocking {
let unblockDomainAction = UIAction(title: L10n.Common.Controls.Actions.unblockDomain(mastodonUser.domainFromAcct), image: UIImage(systemName: "nosign"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in
let unblockDomainAction = UIAction(
title: L10n.Common.Controls.Actions.unblockDomain(mastodonUser.domainFromAcct),
image: UIImage(systemName: "nosign"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .off
) { [weak provider, weak cell] _ in
guard let provider = provider else { return }
guard let cell = cell else { return }
provider.context.blockDomainService.unblockDomain(userProvider: provider, cell: cell)
}
children.append(unblockDomainAction)
} else {
let blockDomainAction = UIAction(title: L10n.Common.Controls.Actions.blockDomain(mastodonUser.domainFromAcct), image: UIImage(systemName: "nosign"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in
let blockDomainAction = UIAction(
title: L10n.Common.Controls.Actions.blockDomain(mastodonUser.domainFromAcct),
image: UIImage(systemName: "nosign"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .off
) { [weak provider, weak cell] _ in
guard let provider = provider else { return }
guard let cell = cell else { return }
let alertController = UIAlertController(title: L10n.Common.Alerts.BlockDomain.title(mastodonUser.domainFromAcct), message: nil, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in
}
let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in }
alertController.addAction(cancelAction)
let blockDomainAction = UIAlertAction(title: L10n.Common.Alerts.BlockDomain.blockEntireDomain, style: .destructive) { _ in
let blockDomainAction = UIAlertAction(title: L10n.Common.Alerts.BlockDomain.blockEntireDomain, style: .destructive) { [weak provider, weak cell] _ in
guard let provider = provider else { return }
guard let cell = cell else { return }
provider.context.blockDomainService.blockDomain(userProvider: provider, cell: cell)
}
alertController.addAction(blockDomainAction)
@ -351,19 +396,26 @@ extension UserProviderFacade {
}
if let status = shareStatus, isMyself {
let deleteAction = UIAction(title: L10n.Common.Controls.Actions.delete, image: UIImage(systemName: "delete.left"), identifier: nil, discoverabilityTitle: nil, attributes: [.destructive], state: .off) {
[weak provider] _ in
let deleteAction = UIAction(
title: L10n.Common.Controls.Actions.delete,
image: UIImage(systemName: "delete.left"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [.destructive],
state: .off
) { [weak provider] _ in
guard let provider = provider else { return }
let alertController = UIAlertController(title: L10n.Common.Alerts.DeletePost.title, message: nil, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in
}
let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in }
alertController.addAction(cancelAction)
let deleteAction = UIAlertAction(title: L10n.Common.Alerts.DeletePost.delete, style: .destructive) { _ in
let deleteAction = UIAlertAction(title: L10n.Common.Alerts.DeletePost.delete, style: .destructive) { [weak provider] _ in
guard let provider = provider else { return }
guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
provider.context.apiService.deleteStatus(domain: activeMastodonAuthenticationBox.domain,
statusID: status.id,
authorizationBox: activeMastodonAuthenticationBox
provider.context.apiService.deleteStatus(
domain: activeMastodonAuthenticationBox.domain,
statusID: status.id,
authorizationBox: activeMastodonAuthenticationBox
)
.sink { _ in
// do nothing
@ -374,7 +426,6 @@ extension UserProviderFacade {
}
alertController.addAction(deleteAction)
provider.present(alertController, animated: true, completion: nil)
}
children.append(deleteAction)
}

View File

@ -17,17 +17,11 @@ extension HashtagTimelineViewModel {
statusTableViewCellDelegate: StatusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate
) {
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
.share()
.eraseToAnyPublisher()
diffableDataSource = StatusSection.tableViewDiffableDataSource(
for: tableView,
timelineContext: .hashtag,
dependency: dependency,
managedObjectContext: context.managedObjectContext,
timestampUpdatePublisher: timestampUpdatePublisher,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: timelineMiddleLoaderTableViewCellDelegate,
threadReplyLoaderTableViewCellDelegate: nil

View File

@ -18,17 +18,11 @@ extension HomeTimelineViewModel {
statusTableViewCellDelegate: StatusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate
) {
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
.share()
.eraseToAnyPublisher()
diffableDataSource = StatusSection.tableViewDiffableDataSource(
for: tableView,
timelineContext: .home,
dependency: dependency,
managedObjectContext: fetchedResultsController.managedObjectContext,
timestampUpdatePublisher: timestampUpdatePublisher,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: timelineMiddleLoaderTableViewCellDelegate,
threadReplyLoaderTableViewCellDelegate: nil

View File

@ -42,6 +42,10 @@ final class NotificationViewController: UIViewController, NeedsDependency {
}()
let refreshControl = UIRefreshControl()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
}
}
extension NotificationViewController {

View File

@ -14,17 +14,11 @@ extension FavoriteViewModel {
dependency: NeedsDependency,
statusTableViewCellDelegate: StatusTableViewCellDelegate
) {
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
.share()
.eraseToAnyPublisher()
diffableDataSource = StatusSection.tableViewDiffableDataSource(
for: tableView,
timelineContext: .favorite,
dependency: dependency,
managedObjectContext: statusFetchedResultsController.fetchedResultsController.managedObjectContext,
timestampUpdatePublisher: timestampUpdatePublisher,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: nil,
threadReplyLoaderTableViewCellDelegate: nil

View File

@ -97,7 +97,7 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi
}
deinit {
os_log("%{public}s[%{public}ld], %{public}s: deinit", ((#file as NSString).lastPathComponent), #line, #function)
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
}
}

View File

@ -14,17 +14,11 @@ extension UserTimelineViewModel {
dependency: NeedsDependency,
statusTableViewCellDelegate: StatusTableViewCellDelegate
) {
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
.share()
.eraseToAnyPublisher()
diffableDataSource = StatusSection.tableViewDiffableDataSource(
for: tableView,
timelineContext: .account,
dependency: dependency,
managedObjectContext: statusFetchedResultsController.fetchedResultsController.managedObjectContext,
timestampUpdatePublisher: timestampUpdatePublisher,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: nil,
threadReplyLoaderTableViewCellDelegate: nil

View File

@ -17,17 +17,11 @@ extension PublicTimelineViewModel {
statusTableViewCellDelegate: StatusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate
) {
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
.share()
.eraseToAnyPublisher()
diffableDataSource = StatusSection.tableViewDiffableDataSource(
for: tableView,
timelineContext: .public,
dependency: dependency,
managedObjectContext: fetchedResultsController.managedObjectContext,
timestampUpdatePublisher: timestampUpdatePublisher,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: timelineMiddleLoaderTableViewCellDelegate,
threadReplyLoaderTableViewCellDelegate: nil

View File

@ -95,6 +95,10 @@ final class SearchViewController: UIViewController, NeedsDependency {
let searchBarTapPublisher = PassthroughSubject<Void, Never>()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
}
}
extension SearchViewController {

View File

@ -111,6 +111,10 @@ final class StatusTableViewCell: UITableViewCell, StatusCell {
_init()
}
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
}
}
extension StatusTableViewCell {

View File

@ -19,17 +19,11 @@ extension ThreadViewModel {
statusTableViewCellDelegate: StatusTableViewCellDelegate,
threadReplyLoaderTableViewCellDelegate: ThreadReplyLoaderTableViewCellDelegate
) {
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
.share()
.eraseToAnyPublisher()
diffableDataSource = StatusSection.tableViewDiffableDataSource(
for: tableView,
timelineContext: .thread,
dependency: dependency,
managedObjectContext: context.managedObjectContext,
timestampUpdatePublisher: timestampUpdatePublisher,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: nil,
threadReplyLoaderTableViewCellDelegate: threadReplyLoaderTableViewCellDelegate