From 7184f1d920a0d8f07bfd02d751cd60186d8de927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=84=EB=A6=AC?= Date: Thu, 14 Nov 2024 00:20:02 +0900 Subject: [PATCH] =?UTF-8?q?[=EB=B2=84=EA=B7=B8]=20withUnretained=20?= =?UTF-8?q?=EA=B1=B7=EC=96=B4=EB=82=B4=EA=B8=B0=20(#73)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐛 [fix] 카탈로그 전체선택 시 앱이 강제종료되는 문제 개선 --- .../ItemDetailViewController.swift | 15 ++--- .../ViewControllers/ItemsViewController.swift | 26 ++++----- .../ViewModels/CatalogCellReactor.swift | 8 ++- .../ViewModels/ItemDetailReactor.swift | 15 +++-- .../Catalog/ViewModels/ItemsReactor.swift | 51 ++++++++++------- .../Catalog/Views/CatalogCell.swift | 5 +- .../Catalog/Views/ItemSeasonView.swift | 11 ++-- .../Catalog/Views/ItemVariantsView.swift | 7 +-- .../CollectionProgressViewController.swift | 3 +- .../CollectionViewController.swift | 3 +- .../ViewControllers/AboutViewController.swift | 3 +- .../CustomTaskViewController.swift | 9 +-- .../PreferencesViewController.swift | 12 ++-- .../TaskEditViewController.swift | 8 +-- .../Views/CollectionProgressView.swift | 9 ++- .../Dashboard/Views/TodaysTasksView.swift | 3 +- .../Dashboard/Views/UserInfoView.swift | 5 +- .../Dashboard/Views/VillagersView.swift | 27 ++++----- .../Dashboard/Views/shared/ProgressView.swift | 7 +-- .../PlayerViewController.swift | 57 +++++++++---------- .../Views/MaximizePlayerView.swift | 38 ++++++------- .../Views/MinimizePlayerView.swift | 19 +++---- .../VillagerDetailViewController.swift | 25 ++++---- .../VillagersViewController.swift | 13 ++--- .../ViewModels/VillagerDetailReactor.swift | 10 ++-- .../ViewModels/VillagersCellReactor.swift | 10 ++-- .../ViewModels/VillagersReactor.swift | 24 +++++--- .../Villagers/Views/VillagersCell.swift | 10 ++-- .../Sources/Utility/MusicPlayerManager.swift | 24 ++++---- 29 files changed, 215 insertions(+), 242 deletions(-) diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewControllers/ItemDetailViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewControllers/ItemDetailViewController.swift index 3f42391c..30e9d702 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewControllers/ItemDetailViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewControllers/ItemDetailViewController.swift @@ -91,10 +91,9 @@ class ItemDetailViewController: UIViewController { reactor.state.map { $0.isAcquired } .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, isAcquired in + .subscribe(onNext: { [weak self] isAcquired in let config = UIImage.SymbolConfiguration(scale: .large) - owner.checkButton.setImage( + self?.checkButton.setImage( UIImage(systemName: isAcquired ? "checkmark.seal.fill" : "checkmark.seal", withConfiguration: config), for: .normal ) @@ -102,16 +101,14 @@ class ItemDetailViewController: UIViewController { itemVariantsColorView?.didTapImage .compactMap { $0 } - .withUnretained(self) - .subscribe(onNext: { owner, image in - owner.itemDetailInfoView?.changeImage(image) + .subscribe(onNext: { [weak self] image in + self?.itemDetailInfoView?.changeImage(image) }).disposed(by: disposeBag) itemVariantsPatternView?.didTapImage .compactMap { $0 } - .withUnretained(self) - .subscribe(onNext: { owner, image in - owner.itemDetailInfoView?.changeImage(image) + .subscribe(onNext: { [weak self] image in + self?.itemDetailInfoView?.changeImage(image) }).disposed(by: disposeBag) } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewControllers/ItemsViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewControllers/ItemsViewController.swift index 574e1db6..324e4187 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewControllers/ItemsViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewControllers/ItemsViewController.swift @@ -191,9 +191,8 @@ class ItemsViewController: UIViewController { selectedKeyword .filter { $0.isEmpty == false } .map { !$0.keys.contains(.all) } - .withUnretained(self) .observe(on: MainScheduler.instance) - .subscribe(onNext: { owner, isFiltering in + .subscribe(with: self, onNext: { owner, isFiltering in owner.navigationItem.rightBarButtonItem?.image = UIImage( systemName: isFiltering ? "arrow.up.arrow.down.circle.fill" : "ellipsis.circle" ) @@ -201,8 +200,7 @@ class ItemsViewController: UIViewController { searchController.searchBar.rx.text .map { $0 != "" } - .withUnretained(self) - .subscribe(onNext: { owner, isSearching in + .subscribe(with: self, onNext: { owner, isSearching in if isSearching { owner.emptyView.editLabel( title: "Item is empty.".localized, @@ -214,8 +212,7 @@ class ItemsViewController: UIViewController { searchController.searchBar.rx.selectedScopeButtonIndex .compactMap { SearchScope.allCases[safe: $0] } .observe(on: MainScheduler.asyncInstance) - .withUnretained(self) - .subscribe(onNext: { owner, currentScope in + .subscribe(with: self, onNext: { owner, currentScope in switch currentScope { case .all: owner.emptyView.editLabel( @@ -390,17 +387,19 @@ extension ItemsViewController { title: Menu.allSelect.title, image: UIImage(systemName: "text.badge.checkmark") ) { [weak self] action in - guard let self = self else { + guard let owner = self else { return } - self.showAlert(title: "Notice".localized, message: "Are you sure you want to check them all?".localized) + owner.showAlert(title: "Notice".localized, message: "Are you sure you want to check them all?".localized) .filter { $0 == true } - .withUnretained(self) - .subscribe(onNext: { owner, _ in + .subscribe(onNext: { [weak owner] _ in + guard let owner else { + return + } owner.reactor.action.onNext(.selectedMenu(keywords: [.allSelect: ""])) owner.selectedKeyword.accept(owner.selectedKeyword.value) - }).disposed(by: self.disposeBag) - self.navigationItem.rightBarButtonItem?.menu = self.createMoreMenu() + }).disposed(by: owner.disposeBag) + owner.navigationItem.rightBarButtonItem?.menu = owner.createMoreMenu() } let resetAction = UIAction( title: Menu.reset.title, @@ -411,8 +410,7 @@ extension ItemsViewController { } self.showAlert(title: "Notice".localized, message: "Are you sure you want to uncheck them all?".localized) .filter { $0 == true } - .withUnretained(self) - .subscribe(onNext: { owner, _ in + .subscribe(with: self, onNext: { owner, _ in owner.reactor.action.onNext(.selectedMenu(keywords: [.reset: ""])) owner.selectedKeyword.accept(owner.selectedKeyword.value) }).disposed(by: self.disposeBag) diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/CatalogCellReactor.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/CatalogCellReactor.swift index b4ca05a9..a9e00019 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/CatalogCellReactor.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/CatalogCellReactor.swift @@ -48,9 +48,11 @@ final class CatalogCellReactor: Reactor { case .fetch: let collectedState = Items.shared.itemList .take(1) - .withUnretained(self) - .compactMap { owner, items in - items[owner.currentState.category]?.contains(owner.item) + .compactMap { [weak self] items in + guard let owner = self else { + return nil + } + return items[owner.currentState.category]?.contains(owner.item) }.map { Mutation.setAcquired($0) } return collectedState diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/ItemDetailReactor.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/ItemDetailReactor.swift index 7e372654..18df6a60 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/ItemDetailReactor.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/ItemDetailReactor.swift @@ -44,10 +44,17 @@ final class ItemDetailReactor: Reactor { case .fetch: let collectedState = Items.shared.itemList .take(1) - .withUnretained(self) - .compactMap { owner, items in - items[owner.currentState.item.category] - }.withUnretained(self).map { owner, items -> Mutation in Mutation.setAcquired(items.contains(owner.currentState.item)) + .compactMap { [weak self] items -> [Item]? in + guard let owner = self else { + return nil + } + return items[owner.currentState.item.category] + } + .compactMap { [weak self] items -> Mutation? in + guard let owner = self else { + return nil + } + return Mutation.setAcquired(items.contains(owner.currentState.item)) } return collectedState diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/ItemsReactor.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/ItemsReactor.swift index 4d1e1220..486f2379 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/ItemsReactor.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/ViewModels/ItemsReactor.swift @@ -75,8 +75,7 @@ final class ItemsReactor: Reactor { let newAllItems = setUpItems().map { Mutation.setAllItems($0) } let collectedItems = setUpUserItem() let notCollectedIems = setUpUserItem() - .withUnretained(self) - .map { owner, items in owner.setUpNotCollected(items) } + .compactMap { [weak self] items in self?.setUpNotCollected(items) } let userItems = Observable.combineLatest(collectedItems, notCollectedIems) .map { Mutation.setUserItems(collected: $0.0, notCollected: $0.1) } let loadingState = Items.shared.isLoading.map { Mutation.setLoadingState($0) } @@ -91,14 +90,21 @@ final class ItemsReactor: Reactor { lastSearchKeyword = text.lowercased() guard text != "" else { return currentItems() - .withUnretained(self) - .map { owner, items in owner.filtered(items: items, keywords: owner.currentKeywords) } + .compactMap { [weak self] items in + guard let owner = self else { + return nil + } + return owner.filtered(items: items, keywords: owner.currentKeywords) + } .map { .setItems($0) } } return currentItems() - .withUnretained(self) - .map { owner, items -> [Item] in - owner.filtered( + .compactMap { [weak self] items -> [Item]? in + guard let owner = self else { + return nil + } + + return owner.filtered( items: owner.search(items: items, text: text.lowercased()), keywords: owner.currentKeywords ) @@ -114,9 +120,9 @@ final class ItemsReactor: Reactor { case .selectedMenu(let keywords): currentKeywords = keywords return currentItems() - .withUnretained(self) - .map { owner, items -> [Item] in - owner.filtered( + .map { [weak self] items -> [Item] in + guard let owner = self else { return [] } + return owner.filtered( items: owner.search(items: items, text: owner.lastSearchKeyword), keywords: keywords ) @@ -258,16 +264,21 @@ final class ItemsReactor: Reactor { switch mode { case .all: return Items.shared.categoryList - .withUnretained(self) - .compactMap { owner, items in - items[owner.currentState.category] + .compactMap { [weak self] items in + guard let owner = self else { + return nil + } + + return items[owner.currentState.category] } case .user: return Items.shared.itemList - .withUnretained(self) - .map { owenr, items in - items[owenr.currentState.category] ?? [] + .map { [weak self] items in + guard let owner = self else { + return [] + } + return items[owner.currentState.category] ?? [] } case .keyword(let title, let category): @@ -280,9 +291,11 @@ final class ItemsReactor: Reactor { switch mode { case .all: return Items.shared.itemList - .withUnretained(self) - .map { owenr, items in - items[owenr.currentState.category] ?? [] + .map { [weak self] items in + guard let owner = self else { + return [] + } + return items[owner.currentState.category] ?? [] } case .keyword(let title, _): diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/CatalogCell.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/CatalogCell.swift index 3f6c2eb5..8134d3f9 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/CatalogCell.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/CatalogCell.swift @@ -76,10 +76,9 @@ class CatalogCell: UICollectionViewCell { reactor.state.map { $0.isAcquired } .compactMap { $0 } .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, isAcquired in + .subscribe(onNext: { [weak self] isAcquired in let config = UIImage.SymbolConfiguration(font: .preferredFont(forTextStyle: .title2)) - owner.checkButton.setImage( + self?.checkButton.setImage( UIImage( systemName: isAcquired ? "checkmark.seal.fill" : "checkmark.seal", withConfiguration: config diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/ItemSeasonView.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/ItemSeasonView.swift index 2c70e2ec..3cf31f0b 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/ItemSeasonView.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/ItemSeasonView.swift @@ -43,16 +43,15 @@ class ItemSeasonView: UIView { Items.shared.userInfo .compactMap { $0?.hemisphere } - .withUnretained(self) .observe(on: MainScheduler.instance) - .subscribe(onNext: { owner, hemisphere in + .subscribe(onNext: { [weak self] hemisphere in switch hemisphere { case .south: - owner.setUpTime(times: item.hemispheres?.south.time ?? []) - owner.setUpCalendar(months: item.hemispheres?.south.monthsArray ?? []) + self?.setUpTime(times: item.hemispheres?.south.time ?? []) + self?.setUpCalendar(months: item.hemispheres?.south.monthsArray ?? []) case .north: - owner.setUpTime(times: item.hemispheres?.north.time ?? []) - owner.setUpCalendar(months: item.hemispheres?.north.monthsArray ?? []) + self?.setUpTime(times: item.hemispheres?.north.time ?? []) + self?.setUpCalendar(months: item.hemispheres?.north.monthsArray ?? []) } }).disposed(by: disposeBag) diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/ItemVariantsView.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/ItemVariantsView.swift index 0c92cce0..6829a6b4 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/ItemVariantsView.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Catalog/Views/ItemVariantsView.swift @@ -65,10 +65,9 @@ class ItemVariantsView: UIView { }.disposed(by: disposeBag) collectionView.rx.itemSelected - .withUnretained(self) - .subscribe(onNext: { owner, indexPath in - let cell = owner.collectionView.cellForItem(at: indexPath) as? VariantCell - owner.cellImage.accept(cell?.imageView.image) + .subscribe(onNext: { [weak self] indexPath in + let cell = self?.collectionView.cellForItem(at: indexPath) as? VariantCell + self?.cellImage.accept(cell?.imageView.image) }).disposed(by: disposeBag) } } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Collection/ViewControllers/CollectionProgressViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Collection/ViewControllers/CollectionProgressViewController.swift index 7f5976e6..82506209 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Collection/ViewControllers/CollectionProgressViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Collection/ViewControllers/CollectionProgressViewController.swift @@ -53,8 +53,7 @@ class CollectionProgressViewController: UIViewController { }.disposed(by: disposeBag) tableView.rx.itemSelected - .withUnretained(self) - .subscribe(onNext: { owner, indexPath in + .subscribe(with: self, onNext: { owner, indexPath in owner.tableView.deselectRow(at: indexPath, animated: true) }).disposed(by: disposeBag) } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Collection/ViewControllers/CollectionViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Collection/ViewControllers/CollectionViewController.swift index 64349c17..1eef88e0 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Collection/ViewControllers/CollectionViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Collection/ViewControllers/CollectionViewController.swift @@ -75,8 +75,7 @@ class CollectionViewController: UIViewController { .disposed(by: disposeBag) tableView.rx.itemSelected - .withUnretained(self) - .subscribe(onNext: { owner, indexPath in + .subscribe(with: self, onNext: { owner, indexPath in owner.tableView.deselectRow(at: indexPath, animated: true) }).disposed(by: disposeBag) } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/AboutViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/AboutViewController.swift index 9d9948de..cdc22868 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/AboutViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/AboutViewController.swift @@ -86,8 +86,7 @@ class AboutViewController: UIViewController { tableView.rx.itemSelected .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, indexPath in + .subscribe(with: self, onNext: { owner, indexPath in owner.tableView.deselectRow(at: indexPath, animated: true) }).disposed(by: disposeBag) diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/CustomTaskViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/CustomTaskViewController.swift index 3003315f..d9f44f05 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/CustomTaskViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/CustomTaskViewController.swift @@ -75,8 +75,7 @@ class CustomTaskViewController: UIViewController { .disposed(by: disposeBag) customTaskSection.maxAmountButtonObservable - .withUnretained(self) - .subscribe(onNext: { owner, _ in + .subscribe(with: self, onNext: { owner, _ in owner.showSelectedItemAlert( Array(1...20).map { $0.description }, currentItem: owner.currentAmount.value @@ -92,16 +91,14 @@ class CustomTaskViewController: UIViewController { reactor.state .compactMap { $0.amount } - .withUnretained(self) - .subscribe(onNext: { owner, amount in + .subscribe(with: self, onNext: { owner, amount in owner.customTaskSection.updateAmount(amount.description) owner.currentAmount.accept(amount.description) }).disposed(by: disposeBag) reactor.state.compactMap { $0.task } .filter { [weak self] in self?.currentTask.value != $0 } - .withUnretained(self) - .subscribe(onNext: { owner, task in + .subscribe(with: self, onNext: { owner, task in owner.customTaskSection.setUpViews(task) owner.currentAmount.accept(task.amount.description) owner.currentTask.accept(task) diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/PreferencesViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/PreferencesViewController.swift index c39c54c6..a164d701 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/PreferencesViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/PreferencesViewController.swift @@ -68,8 +68,7 @@ class PreferencesViewController: UIViewController { .disposed(by: disposeBag) settingSection.hemisphereButtonObservable - .withUnretained(self) - .subscribe(onNext: { owner, _ in + .subscribe(with: self, onNext: { owner, _ in owner.showSelectedItemAlert( Hemisphere.allCases.map { $0.rawValue.localized }, currentItem: owner.currentHemisphere.value @@ -79,8 +78,7 @@ class PreferencesViewController: UIViewController { }).disposed(by: disposeBag) settingSection.reputationButtonObservable - .withUnretained(self) - .subscribe(onNext: { owner, _ in + .subscribe(with: self, onNext: { owner, _ in owner.showSelectedItemAlert( ["⭐️", "⭐️⭐️", "⭐️⭐️⭐️", "⭐️⭐️⭐️⭐️", "⭐️⭐️⭐️⭐️⭐️"], currentItem: owner.currentReputation.value @@ -90,8 +88,7 @@ class PreferencesViewController: UIViewController { }).disposed(by: disposeBag) settingSection.startingFruitButtonObservable - .withUnretained(self) - .subscribe(onNext: { owner, _ in + .subscribe(with: self, onNext: { owner, _ in owner.showSelectedItemAlert( Fruit.allCases.map { $0.rawValue.lowercased().localized }, currentItem: owner.currentFruit.value @@ -103,8 +100,7 @@ class PreferencesViewController: UIViewController { reactor.state .compactMap { $0.userInfo } .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, userInfo in + .subscribe(with: self, onNext: { owner, userInfo in owner.settingSection.setUpViews(userInfo) owner.currentHemisphere.accept(userInfo.hemisphere.rawValue.localized) owner.currentFruit.accept(userInfo.islandFruit.rawValue.localized) diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/TaskEditViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/TaskEditViewController.swift index d2828858..faf480cc 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/TaskEditViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/ViewControllers/TaskEditViewController.swift @@ -94,10 +94,10 @@ class TaskEditViewController: UIViewController { }.disposed(by: disposeBag) tableView.rx.itemSelected - .withUnretained(self) - .subscribe(onNext: { owner, indexPath in - owner.tableView.deselectRow(at: indexPath, animated: true) - }).disposed(by: disposeBag) + .subscribe(onNext: { [weak self] indexPath in + self?.tableView.deselectRow(at: indexPath, animated: true) + }) + .disposed(by: disposeBag) } } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/CollectionProgressView.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/CollectionProgressView.swift index 4286a4ad..4ca11539 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/CollectionProgressView.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/CollectionProgressView.swift @@ -78,13 +78,12 @@ class CollectionProgressView: UIView { Items.shared.itemsCount .map { $0.isEmpty } - .withUnretained(self) - .subscribe(onNext: { owner, isEmpty in - owner.emptyView.isHidden = !isEmpty + .subscribe(onNext: { [weak self] isEmpty in + self?.emptyView.isHidden = !isEmpty if isEmpty { - owner.removeGestureRecognizer(tap) + self?.removeGestureRecognizer(tap) } else { - owner.addGestureRecognizer(tap) + self?.addGestureRecognizer(tap) } }) .disposed(by: disposeBag) diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/TodaysTasksView.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/TodaysTasksView.swift index bbd05f4a..0b7ac20d 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/TodaysTasksView.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/TodaysTasksView.swift @@ -124,8 +124,7 @@ class TodaysTasksView: UIView { }).disposed(by: disposeBag) collectionView.rx.itemSelected - .withUnretained(self) - .subscribe(onNext: { owner, indexPath in + .subscribe(with: self, onNext: { owner, indexPath in let cell = owner.collectionView.cellForItem(at: indexPath) as? IconCell cell?.toggle() HapticManager.shared.selection() diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/UserInfoView.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/UserInfoView.swift index 2f062682..2eb2d41b 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/UserInfoView.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/UserInfoView.swift @@ -96,10 +96,9 @@ class UserInfoView: UIView { reactor.state.map { $0.userInfo } .compactMap { $0 } - .withUnretained(self) .observe(on: MainScheduler.instance) - .subscribe(onNext: { owner, userInfo in - owner.updateInfo(userInfo) + .subscribe(onNext: { [weak self] userInfo in + self?.updateInfo(userInfo) }).disposed(by: disposeBag) } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/VillagersView.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/VillagersView.swift index 438c06e0..31f302ff 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/VillagersView.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/VillagersView.swift @@ -132,33 +132,30 @@ class VillagersView: UIView { reactor.state .map { $0.villagers } - .withUnretained(self) .observe(on: MainScheduler.asyncInstance) - .subscribe(onNext: { owner, villagers in + .subscribe(onNext: { [weak self] villagers in if villagers.isEmpty { - owner.emptyLabel.isHidden = false - owner.backgroundStackView.isHidden = true + self?.emptyLabel.isHidden = false + self?.backgroundStackView.isHidden = true } else { - owner.emptyLabel.isHidden = true - owner.backgroundStackView.isHidden = false - owner.descriptionLabel.text = "tip".localized + self?.emptyLabel.isHidden = true + self?.backgroundStackView.isHidden = false + self?.descriptionLabel.text = "tip".localized } - owner.updateCollectionViewHeight() - owner.layoutIfNeeded() + self?.updateCollectionViewHeight() + self?.layoutIfNeeded() }).disposed(by: disposeBag) collectionView.rx.itemSelected - .withUnretained(self) - .subscribe(onNext: { owner, indexPath in + .subscribe(onNext: { [weak self] indexPath in HapticManager.shared.selection() - let cell = owner.collectionView.cellForItem(at: indexPath) as? IconCell + let cell = self?.collectionView.cellForItem(at: indexPath) as? IconCell cell?.checkMark() }).disposed(by: disposeBag) resetButton.rx.tap - .withUnretained(self) - .subscribe(onNext: { owner, _ in - let cells = owner.collectionView.visibleCells as? [IconCell] + .subscribe(onNext: { [weak self] _ in + let cells = self?.collectionView.visibleCells as? [IconCell] cells?.forEach { $0.removeCheckMark() } }).disposed(by: disposeBag) } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/shared/ProgressView.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/shared/ProgressView.swift index 6edd9ee9..1d93747d 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/shared/ProgressView.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Dashboard/Views/shared/ProgressView.swift @@ -53,11 +53,10 @@ class ProgressView: UIStackView { .disposed(by: disposeBag) reactor.state.map { $0.itemInfo } - .withUnretained(self) .observe(on: MainScheduler.instance) - .subscribe(onNext: { owner, items in - owner.progressLabel.text = "\(items.itemCount) / \(items.maxCount)" - owner.progressBar.setProgress(Float(items.itemCount) / Float(items.maxCount), animated: false) + .subscribe(onNext: { [weak self] items in + self?.progressLabel.text = "\(items.itemCount) / \(items.maxCount)" + self?.progressBar.setProgress(Float(items.itemCount) / Float(items.maxCount), animated: false) }).disposed(by: disposeBag) } } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/ViewControllers/PlayerViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/ViewControllers/PlayerViewController.swift index 2324b0df..6ae0d494 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/ViewControllers/PlayerViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/ViewControllers/PlayerViewController.swift @@ -78,9 +78,8 @@ class PlayerViewController: UIViewController { }).disposed(by: disposeBag) dragGesture.rx.event - .withUnretained(self) - .map { owner, gestureRecognizer -> Bool? in - let velocity = gestureRecognizer.velocity(in: owner.visualEffectView) + .map { [weak self] gestureRecognizer -> Bool? in + let velocity = gestureRecognizer.velocity(in: self?.visualEffectView) if gestureRecognizer.state == .ended { if velocity.y < 0 { return true @@ -147,38 +146,37 @@ class PlayerViewController: UIViewController { }).disposed(by: disposeBag) reactor.state.map { $0.playerMode } - .withUnretained(self) - .subscribe(onNext: { owner, playerMode in + .subscribe(onNext: { [weak self] playerMode in switch playerMode { case .large: UIView.animate(withDuration: 0.25) { - owner.maximizeView.alpha = 1 - owner.minimizeView.alpha = 0 - owner.tableView.alpha = 0 + self?.maximizeView.alpha = 1 + self?.minimizeView.alpha = 0 + self?.tableView.alpha = 0 } completion: { _ in - owner.maximizeView.isHidden = false - owner.minimizeView.isHidden = true - owner.tableView.isHidden = true + self?.maximizeView.isHidden = false + self?.minimizeView.isHidden = true + self?.tableView.isHidden = true } case .small: UIView.animate(withDuration: 0.25) { - owner.maximizeView.alpha = 0 - owner.minimizeView.alpha = 1 - owner.tableView.alpha = 0 + self?.maximizeView.alpha = 0 + self?.minimizeView.alpha = 1 + self?.tableView.alpha = 0 } completion: { _ in - owner.maximizeView.isHidden = true - owner.tableView.isHidden = true - owner.minimizeView.isHidden = false + self?.maximizeView.isHidden = true + self?.tableView.isHidden = true + self?.minimizeView.isHidden = false } case .list: UIView.animate(withDuration: 0.25) { - owner.maximizeView.alpha = 0 - owner.minimizeView.alpha = 1 - owner.tableView.alpha = 1 + self?.maximizeView.alpha = 0 + self?.minimizeView.alpha = 1 + self?.tableView.alpha = 1 } completion: { _ in - owner.maximizeView.isHidden = true - owner.tableView.isHidden = false - owner.minimizeView.isHidden = false + self?.maximizeView.isHidden = true + self?.tableView.isHidden = false + self?.minimizeView.isHidden = false } } }).disposed(by: disposeBag) @@ -190,16 +188,15 @@ class PlayerViewController: UIViewController { reactor.state.map { $0.songs } .filter { $0.isEmpty == false } - .withUnretained(self) - .subscribe(onNext: { owner, _ in + .flatMapLatest { _ in MusicPlayerManager.shared.playingSongIndex .compactMap { $0 } .map { IndexPath(row: $0, section: .zero) } - .withUnretained(self) - .subscribe(onNext: { owner, indexPath in - owner.tableView.selectRow(at: indexPath, animated: true, scrollPosition: .top) - }).disposed(by: owner.disposeBag) - }).disposed(by: disposeBag) + } + .subscribe(onNext: { [weak self] indexPath in + self?.tableView.selectRow(at: indexPath, animated: true, scrollPosition: .top) + }) + .disposed(by: disposeBag) } } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/Views/MaximizePlayerView.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/Views/MaximizePlayerView.swift index 05346e95..3af47dfc 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/Views/MaximizePlayerView.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/Views/MaximizePlayerView.swift @@ -185,8 +185,7 @@ class MaximizePlayerView: UIView { private func bind() { MusicPlayerManager.shared.isNowPlaying .compactMap { $0 } - .withUnretained(self) - .subscribe(onNext: { owner, isPlaying in + .subscribe(with: self, onNext: { owner, isPlaying in let config = UIImage.SymbolConfiguration(font: UIFont.preferredFont(for: .largeTitle, weight: .bold)) owner.playButton.setImage( UIImage(systemName: isPlaying ? "pause.fill" : "play.fill")?.withConfiguration(config), @@ -196,47 +195,42 @@ class MaximizePlayerView: UIView { MusicPlayerManager.shared.currentMusic .compactMap { $0 } - .withUnretained(self) - .subscribe(onNext: { owner, song in + .subscribe(with: self, onNext: { owner, song in owner.coverImageView.kf.cancelDownloadTask() owner.titleLabel.text = song.translations.localizedName() owner.coverImageView.setImage(with: song.image ?? "") }).disposed(by: disposeBag) MusicPlayerManager.shared.songProgress - .withUnretained(self) - .subscribe(onNext: { owner, value in - owner.durationBar.setProgress(value, animated: false) + .subscribe(onNext: { [weak self] value in + self?.durationBar.setProgress(value, animated: false) }).disposed(by: disposeBag) MusicPlayerManager.shared.currentTime - .withUnretained(self) - .subscribe(onNext: { owner, value in - owner.timeElaspedLabel.text = value + .subscribe(onNext: { [weak self] value in + self?.timeElaspedLabel.text = value }).disposed(by: disposeBag) MusicPlayerManager.shared.fullTime .filter { self.durationLabel.text != $0 } - .withUnretained(self) - .subscribe(onNext: { owner, value in - owner.durationLabel.text = value + .subscribe(onNext: { [weak self] value in + self?.durationLabel.text = value }).disposed(by: disposeBag) MusicPlayerManager.shared.currentPlayerMode - .withUnretained(self) - .subscribe(onNext: { owner, playerMode in + .subscribe(onNext: { [weak self] playerMode in let config = UIImage.SymbolConfiguration(font: UIFont.preferredFont(for: .title3, weight: .semibold)) switch playerMode { case .fullRepeat: - owner.repeatButton.setImage(UIImage(systemName: "repeat")?.withConfiguration(config), for: .normal) - owner.repeatButton.tintColor = .acHeaderBackground - owner.shuffleButton.tintColor = .acText + self?.repeatButton.setImage(UIImage(systemName: "repeat")?.withConfiguration(config), for: .normal) + self?.repeatButton.tintColor = .acHeaderBackground + self?.shuffleButton.tintColor = .acText case .oneSongRepeat: - owner.repeatButton.setImage(UIImage(systemName: "repeat.1")?.withConfiguration(config), for: .normal) - owner.repeatButton.tintColor = .acHeaderBackground + self?.repeatButton.setImage(UIImage(systemName: "repeat.1")?.withConfiguration(config), for: .normal) + self?.repeatButton.tintColor = .acHeaderBackground case .shuffle: - owner.shuffleButton.tintColor = .acHeaderBackground - owner.repeatButton.tintColor = .acText + self?.shuffleButton.tintColor = .acHeaderBackground + self?.repeatButton.tintColor = .acText } }).disposed(by: disposeBag) } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/Views/MinimizePlayerView.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/Views/MinimizePlayerView.swift index b15f83fc..012ef491 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/Views/MinimizePlayerView.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/MusicPlayer/Views/MinimizePlayerView.swift @@ -95,10 +95,9 @@ class MinimizePlayerView: UIView { private func bind() { MusicPlayerManager.shared.isNowPlaying .compactMap { $0 } - .withUnretained(self) - .subscribe(onNext: { owner, isPlaying in + .subscribe(onNext: { [weak self] isPlaying in let config = UIImage.SymbolConfiguration(scale: .large) - owner.playButton.setImage( + self?.playButton.setImage( UIImage(systemName: isPlaying ? "pause.fill" : "play.fill")?.withConfiguration(config), for: .normal ) @@ -106,17 +105,15 @@ class MinimizePlayerView: UIView { MusicPlayerManager.shared.currentMusic .compactMap { $0 } - .withUnretained(self) - .subscribe(onNext: { owner, song in - owner.coverImageView.kf.cancelDownloadTask() - owner.titleLabel.text = song.translations.localizedName() - owner.coverImageView.setImage(with: song.image ?? "") + .subscribe(onNext: { [weak self] song in + self?.coverImageView.kf.cancelDownloadTask() + self?.titleLabel.text = song.translations.localizedName() + self?.coverImageView.setImage(with: song.image ?? "") }).disposed(by: disposeBag) MusicPlayerManager.shared.songProgress - .withUnretained(self) - .subscribe(onNext: { owner, value in - owner.durationBar.setProgress(value, animated: false) + .subscribe(onNext: { [weak self] value in + self?.durationBar.setProgress(value, animated: false) }).disposed(by: disposeBag) } } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewControllers/VillagerDetailViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewControllers/VillagerDetailViewController.swift index ce2e3e83..2b0c5208 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewControllers/VillagerDetailViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewControllers/VillagerDetailViewController.swift @@ -40,8 +40,7 @@ class VillagerDetailViewController: UIViewController { action: nil ) navigationItem.leftBarButtonItem?.rx.tap - .withUnretained(self) - .subscribe(onNext: { owner, _ in + .subscribe(with: self, onNext: { owner, _ in owner.dismiss(animated: true) }).disposed(by: disposeBag) } @@ -86,9 +85,8 @@ class VillagerDetailViewController: UIViewController { reactor.state.map { $0.isLiked } .compactMap { $0 } .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, isLiked in - owner.likeButton.setImage( + .subscribe(onNext: { [weak self] isLiked in + self?.likeButton.setImage( UIImage(systemName: isLiked ? "heart.fill" : "heart")?.withConfiguration(buttonConfigure), for: .normal ) @@ -97,9 +95,8 @@ class VillagerDetailViewController: UIViewController { reactor.state.map { $0.isResident } .compactMap { $0 } .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, isResident in - owner.houseButton.setImage( + .subscribe(onNext: { [weak self] isResident in + self?.houseButton.setImage( UIImage(systemName: isResident ? "house.fill" : "house")?.withConfiguration(buttonConfigure), for: .normal ) @@ -108,19 +105,17 @@ class VillagerDetailViewController: UIViewController { reactor.state.map { $0.villager } .take(1) .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, villager in + .subscribe(onNext: { [weak self] villager in let detailSection = VillagerDetailView(villager) - owner.sectionsScrollView.addSection(SectionView(contentView: detailSection)) - owner.navigationItem.title = villager.translations.localizedName() + self?.sectionsScrollView.addSection(SectionView(contentView: detailSection)) + self?.navigationItem.title = villager.translations.localizedName() }).disposed(by: disposeBag) reactor.state.compactMap { $0.villager.houseImage } .take(1) .observe(on: MainScheduler.asyncInstance) - .withUnretained(self) - .subscribe(onNext: { owner, houseImage in - owner.addHouseSection(houseImage) + .subscribe(onNext: { [weak self] houseImage in + self?.addHouseSection(houseImage) }).disposed(by: disposeBag) } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewControllers/VillagersViewController.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewControllers/VillagersViewController.swift index 4bbbe5ce..4aa0d266 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewControllers/VillagersViewController.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewControllers/VillagersViewController.swift @@ -111,10 +111,9 @@ class VillagersViewController: UIViewController { searchController.searchBar.rx.text .map { $0 != "" } - .withUnretained(self) - .subscribe(onNext: { owner, isSearching in + .subscribe(onNext: { [weak self] isSearching in if isSearching { - owner.emptyView.editLabel( + self?.emptyView.editLabel( title: "There are no villagers.".localized, description: "There are no results for your search.".localized ) @@ -154,8 +153,7 @@ class VillagersViewController: UIViewController { searchController.searchBar.rx.selectedScopeButtonIndex .observe(on: MainScheduler.asyncInstance) .compactMap { SearchScope.allCases[safe: $0] } - .withUnretained(self) - .subscribe(onNext: { owner, currentScope in + .subscribe(with: self, onNext: { owner, currentScope in switch currentScope { case .all: owner.emptyView.editLabel( @@ -179,10 +177,9 @@ class VillagersViewController: UIViewController { selectedKeyword .map { !$0.keys.contains(.all) } - .withUnretained(self) .observe(on: MainScheduler.instance) - .subscribe(onNext: { owner, isFiltering in - owner.navigationItem.rightBarButtonItem?.image = UIImage( + .subscribe(onNext: { [weak self] isFiltering in + self?.navigationItem.rightBarButtonItem?.image = UIImage( systemName: isFiltering ? "arrow.up.arrow.down.circle.fill" : "arrow.up.arrow.down.circle" ) }).disposed(by: disposeBag) diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagerDetailReactor.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagerDetailReactor.swift index 2f620dac..104fa32d 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagerDetailReactor.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagerDetailReactor.swift @@ -51,15 +51,13 @@ final class VillagerDetailReactor: Reactor { case .fetch: let houseState = Items.shared.villagerHouseList .take(1) - .withUnretained(self) - .map { owner, villagers in - villagers.contains(where: { $0.name == owner.villager.name }) + .map { [weak self] villagers in + villagers.contains(where: { $0.name == self?.villager.name }) }.map { Mutation.setHouse($0) } let likeState = Items.shared.villagerLikeList .take(1) - .withUnretained(self) - .map { owner, villagers in - villagers.contains(where: { $0.name == owner.villager.name }) + .map { [weak self] villagers in + villagers.contains(where: { $0.name == self?.villager.name }) }.map { Mutation.setLike($0) } return .merge([ houseState, diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagersCellReactor.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagersCellReactor.swift index 3e06d0d4..4d0b2707 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagersCellReactor.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagersCellReactor.swift @@ -50,15 +50,13 @@ final class VillagersCellReactor: Reactor { case .fetch: let houseState = Items.shared.villagerHouseList .take(1) - .withUnretained(self) - .map { owner, villagers in - villagers.contains(where: { $0.name == owner.villager.name }) + .map { [weak self] villagers in + villagers.contains(where: { $0.name == self?.villager.name }) }.map { Mutation.setHouse($0) } let likeState = Items.shared.villagerLikeList .take(1) - .withUnretained(self) - .map { owner, villagers in - villagers.contains(where: { $0.name == owner.villager.name }) + .map { [weak self] villagers in + villagers.contains(where: { $0.name == self?.villager.name }) }.map { Mutation.setLike($0) } return .merge([ houseState, diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagersReactor.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagersReactor.swift index b1f513b2..092b3538 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagersReactor.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/ViewModels/VillagersReactor.swift @@ -68,15 +68,19 @@ final class VillagersReactor: Reactor { lastSearchKeyword = text.lowercased() guard text != "" else { return currentVillagers() - .withUnretained(self) - .map { owner, villagers in - owner.filtered(villagers: villagers, keywords: owner.currentKeywords) + .compactMap { [weak self] villagers in + guard let owner = self else { + return nil + } + return owner.filtered(villagers: villagers, keywords: owner.currentKeywords) }.map { Mutation.setVillagers($0) } } return currentVillagers() - .withUnretained(self) - .map { owner, villagers in - owner.filtered( + .compactMap { [weak self] villagers in + guard let owner = self else { + return nil + } + return owner.filtered( villagers: owner.search(villagers: villagers, text: text.lowercased()), keywords: owner.currentKeywords ) @@ -92,9 +96,11 @@ final class VillagersReactor: Reactor { case .selectedMenu(let keywords): currentKeywords = keywords return currentVillagers() - .withUnretained(self) - .map { owner, villagers in - owner.filtered( + .compactMap { [weak self] villagers in + guard let owner = self else { + return nil + } + return owner.filtered( villagers: owner.search(villagers: villagers, text: owner.lastSearchKeyword), keywords: keywords ) diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/Views/VillagersCell.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/Views/VillagersCell.swift index 12a5563d..a8b89b42 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/Views/VillagersCell.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Presentation/Villagers/Views/VillagersCell.swift @@ -61,17 +61,15 @@ class VillagersCell: UICollectionViewCell { reactor.state.map { $0.isLiked } .compactMap { $0 } .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, isLiked in - owner.likeButton.setImage(UIImage(systemName: isLiked ? "heart.fill" : "heart"), for: .normal) + .subscribe(onNext: { [weak self] isLiked in + self?.likeButton.setImage(UIImage(systemName: isLiked ? "heart.fill" : "heart"), for: .normal) }).disposed(by: disposeBag) reactor.state.map { $0.isResident } .compactMap { $0 } .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, isResident in - owner.houseButton.setImage(UIImage(systemName: isResident ? "house.fill" : "house"), for: .normal) + .subscribe(onNext: { [weak self] isResident in + self?.houseButton.setImage(UIImage(systemName: isResident ? "house.fill" : "house"), for: .normal) }).disposed(by: disposeBag) } diff --git a/Animal-Crossing-Wiki/Projects/App/Sources/Utility/MusicPlayerManager.swift b/Animal-Crossing-Wiki/Projects/App/Sources/Utility/MusicPlayerManager.swift index 9e40d3e4..6dc4e308 100644 --- a/Animal-Crossing-Wiki/Projects/App/Sources/Utility/MusicPlayerManager.swift +++ b/Animal-Crossing-Wiki/Projects/App/Sources/Utility/MusicPlayerManager.swift @@ -40,8 +40,7 @@ final class MusicPlayerManager { private init() { Items.shared.categoryList .compactMap { $0[.songs] } - .withUnretained(self) - .subscribe(onNext: { owner, songs in + .subscribe(with: self, onNext: { owner, songs in var newSongs = [String: Item]() songs.forEach { item in newSongs[item.name] = item @@ -53,32 +52,29 @@ final class MusicPlayerManager { currentSong .compactMap { $0?.musicURL } .compactMap { URL(string: $0) } - .withUnretained(self) - .subscribe(onNext: { owner, musicURL in + .subscribe(with: self, onNext: { owner, musicURL in owner.player = AVPlayer(url: musicURL) }).disposed(by: disposeBag) currentSong .compactMap { $0 } - .withUnretained(self) - .subscribe(onNext: { owner, song in + .subscribe(with: self, onNext: { owner, song in owner.currentIndex.accept(owner.songsItem.value.firstIndex(of: song)) }).disposed(by: disposeBag) isPlaying .compactMap { $0 } - .withUnretained(self) - .subscribe(onNext: { owner, isPlaying in + .subscribe(onNext: { [weak self] isPlaying in if isPlaying { - if owner.currentSong.value == nil { - owner.currentSong.accept(owner.songsItem.value.first) + if self?.currentSong.value == nil { + self?.currentSong.accept(self?.songsItem.value.first) } - owner.setUpBackground() - owner.player?.play() + self?.setUpBackground() + self?.player?.play() } else { - owner.player?.pause() + self?.player?.pause() } - owner.setUpPlayerTimer() + self?.setUpPlayerTimer() }).disposed(by: disposeBag) setUpNotification()