diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 2a3ecc0e5..1776ef85b 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -76,7 +76,7 @@ jobs:
test:
name: ๐งช Test
- runs-on: macos-14
+ runs-on: macos-15
needs: prepare-ci
steps:
diff --git a/.gitignore b/.gitignore
index fa1024f89..22750e19e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -113,4 +113,4 @@ amplifytools.xcconfig
GoogleService-Info.plist
### Needle
-Projects/App/Sources/Application/NeedleGenerated.swift
\ No newline at end of file
+# Projects/App/Sources/Application/NeedleGenerated.swift
diff --git a/.mise.toml b/.mise.toml
index 58d10e97a..540136578 100644
--- a/.mise.toml
+++ b/.mise.toml
@@ -1,2 +1,2 @@
[tools]
-tuist = "4.12.1"
+tuist = "4.33.0"
diff --git a/Package.resolved b/Package.resolved
index c78bfb278..8344d4e3c 100644
--- a/Package.resolved
+++ b/Package.resolved
@@ -194,8 +194,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/naver/naveridlogin-sdk-ios.git",
"state" : {
- "branch" : "master",
- "revision" : "d8d2128b8bcef8cd93068a058ea898d6dbb7d486"
+ "revision" : "0d89660344926a625824387a130f7e38e0fad2d7",
+ "version" : "4.2.3"
}
},
{
diff --git a/Package.swift b/Package.swift
index abbaa67c8..3c5a3ad6d 100644
--- a/Package.swift
+++ b/Package.swift
@@ -34,7 +34,7 @@ let package = Package(
.package(url: "https://github.com/RxSwiftCommunity/RxDataSources.git", from: "5.0.2"),
.package(url: "https://github.com/RxSwiftCommunity/RxKeyboard.git", from: "2.0.1"),
.package(url: "https://github.com/huri000/SwiftEntryKit", from: "2.0.0"),
- .package(url: "https://github.com/naver/naveridlogin-sdk-ios.git", branch: "master"),
+ .package(url: "https://github.com/naver/naveridlogin-sdk-ios.git", from: "4.2.3"),
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.8.2"),
.package(url: "https://github.com/cbpowell/MarqueeLabel.git", from: "4.5.0"),
.package(url: "https://github.com/firebase/firebase-ios-sdk.git", from: "10.25.0"),
diff --git a/Plugin/EnvironmentPlugin/ProjectDescriptionHelpers/ProjectEnvironment.swift b/Plugin/EnvironmentPlugin/ProjectDescriptionHelpers/ProjectEnvironment.swift
index 8767036f4..eaff19446 100644
--- a/Plugin/EnvironmentPlugin/ProjectDescriptionHelpers/ProjectEnvironment.swift
+++ b/Plugin/EnvironmentPlugin/ProjectDescriptionHelpers/ProjectEnvironment.swift
@@ -24,5 +24,7 @@ public let env = ProjectEnvironment(
.debugInformationFormat(DebugInformationFormat.dwarfWithDsym)
.otherLinkerFlags(["-ObjC"])
.bitcodeEnabled(false)
+ .swiftVersion("6.0")
+ .merging(["SWIFT_STRICT_CONCURRENCY": .string("complete")])
)
diff --git a/Projects/App/Sources/Application/AppComponent+App.swift b/Projects/App/Sources/Application/AppComponent+App.swift
index ac03e8760..3485ea3a1 100644
--- a/Projects/App/Sources/Application/AppComponent+App.swift
+++ b/Projects/App/Sources/Application/AppComponent+App.swift
@@ -1,5 +1,6 @@
import AppDomain
import AppDomainInterface
+@preconcurrency import NeedleFoundation
// MARK: ๋ณ์๋ช
์ฃผ์
// AppComponent ๋ด ๋ณ์ == Dependency ๋ด ๋ณ์ ์ด๋ฆ ๊ฐ์์ผํจ
diff --git a/Projects/App/Sources/Application/AppComponent+Artist.swift b/Projects/App/Sources/Application/AppComponent+Artist.swift
index 1c7c96532..31b3fc370 100644
--- a/Projects/App/Sources/Application/AppComponent+Artist.swift
+++ b/Projects/App/Sources/Application/AppComponent+Artist.swift
@@ -2,6 +2,7 @@ import ArtistDomain
import ArtistDomainInterface
import ArtistFeature
import ArtistFeatureInterface
+@preconcurrency import NeedleFoundation
public extension AppComponent {
// MARK: Artist
diff --git a/Projects/App/Sources/Application/AppComponent+Auth.swift b/Projects/App/Sources/Application/AppComponent+Auth.swift
index f731fde47..40cc21d1f 100644
--- a/Projects/App/Sources/Application/AppComponent+Auth.swift
+++ b/Projects/App/Sources/Application/AppComponent+Auth.swift
@@ -3,6 +3,7 @@ import AuthDomainInterface
import BaseFeature
import MyInfoFeature
import MyInfoFeatureInterface
+@preconcurrency import NeedleFoundation
import SignInFeature
import SignInFeatureInterface
import StorageFeature
diff --git a/Projects/App/Sources/Application/AppComponent+Base.swift b/Projects/App/Sources/Application/AppComponent+Base.swift
index 5387df404..124a301ec 100644
--- a/Projects/App/Sources/Application/AppComponent+Base.swift
+++ b/Projects/App/Sources/Application/AppComponent+Base.swift
@@ -1,6 +1,7 @@
import BaseFeature
import BaseFeatureInterface
import Foundation
+@preconcurrency import NeedleFoundation
public extension AppComponent {
var multiPurposePopupFactory: any MultiPurposePopupFactory {
diff --git a/Projects/App/Sources/Application/AppComponent+Chart.swift b/Projects/App/Sources/Application/AppComponent+Chart.swift
index 83a90a6af..f6e1a8d84 100644
--- a/Projects/App/Sources/Application/AppComponent+Chart.swift
+++ b/Projects/App/Sources/Application/AppComponent+Chart.swift
@@ -3,6 +3,7 @@ import ChartDomain
import ChartDomainInterface
import ChartFeature
import ChartFeatureInterface
+@preconcurrency import NeedleFoundation
public extension AppComponent {
var chartFactory: any ChartFactory {
diff --git a/Projects/App/Sources/Application/AppComponent+Credit.swift b/Projects/App/Sources/Application/AppComponent+Credit.swift
index c59d3f88c..46f2b94a0 100644
--- a/Projects/App/Sources/Application/AppComponent+Credit.swift
+++ b/Projects/App/Sources/Application/AppComponent+Credit.swift
@@ -2,6 +2,7 @@ import CreditDomain
import CreditDomainInterface
import CreditSongListFeature
import CreditSongListFeatureInterface
+@preconcurrency import NeedleFoundation
import SongCreditFeature
import SongCreditFeatureInterface
diff --git a/Projects/App/Sources/Application/AppComponent+Faq.swift b/Projects/App/Sources/Application/AppComponent+Faq.swift
index 12bb97865..21d589cc2 100644
--- a/Projects/App/Sources/Application/AppComponent+Faq.swift
+++ b/Projects/App/Sources/Application/AppComponent+Faq.swift
@@ -1,6 +1,7 @@
import BaseFeature
import FaqDomain
import FaqDomainInterface
+@preconcurrency import NeedleFoundation
import SignInFeature
// MARK: ๋ณ์๋ช
์ฃผ์
diff --git a/Projects/App/Sources/Application/AppComponent+Fruit.swift b/Projects/App/Sources/Application/AppComponent+Fruit.swift
index 538722956..1110f25eb 100644
--- a/Projects/App/Sources/Application/AppComponent+Fruit.swift
+++ b/Projects/App/Sources/Application/AppComponent+Fruit.swift
@@ -1,6 +1,7 @@
import Foundation
import FruitDrawFeature
import FruitDrawFeatureInterface
+@preconcurrency import NeedleFoundation
extension AppComponent {
var fruitDrawFactory: any FruitDrawFactory {
diff --git a/Projects/App/Sources/Application/AppComponent+Image.swift b/Projects/App/Sources/Application/AppComponent+Image.swift
index 13a531cbb..28f680fe0 100644
--- a/Projects/App/Sources/Application/AppComponent+Image.swift
+++ b/Projects/App/Sources/Application/AppComponent+Image.swift
@@ -1,5 +1,6 @@
import ImageDomain
import ImageDomainInterface
+@preconcurrency import NeedleFoundation
// MARK: ๋ณ์๋ช
์ฃผ์
// AppComponent ๋ด ๋ณ์ == Dependency ๋ด ๋ณ์ ์ด๋ฆ ๊ฐ์์ผํจ
diff --git a/Projects/App/Sources/Application/AppComponent+Like.swift b/Projects/App/Sources/Application/AppComponent+Like.swift
index 680caa3db..40eafdeae 100644
--- a/Projects/App/Sources/Application/AppComponent+Like.swift
+++ b/Projects/App/Sources/Application/AppComponent+Like.swift
@@ -1,6 +1,7 @@
import BaseFeature
import LikeDomain
import LikeDomainInterface
+@preconcurrency import NeedleFoundation
import SignInFeature
import StorageFeature
diff --git a/Projects/App/Sources/Application/AppComponent+MyInfo.swift b/Projects/App/Sources/Application/AppComponent+MyInfo.swift
index 9535416f7..0bc77a1f4 100644
--- a/Projects/App/Sources/Application/AppComponent+MyInfo.swift
+++ b/Projects/App/Sources/Application/AppComponent+MyInfo.swift
@@ -1,6 +1,7 @@
import Foundation
import MyInfoFeature
import MyInfoFeatureInterface
+@preconcurrency import NeedleFoundation
extension AppComponent {
var myInfoFactory: any MyInfoFactory {
diff --git a/Projects/App/Sources/Application/AppComponent+Notice.swift b/Projects/App/Sources/Application/AppComponent+Notice.swift
index 3a4b64c28..7ab44a03e 100644
--- a/Projects/App/Sources/Application/AppComponent+Notice.swift
+++ b/Projects/App/Sources/Application/AppComponent+Notice.swift
@@ -2,6 +2,7 @@ import BaseFeature
import MainTabFeature
import MyInfoFeature
import MyInfoFeatureInterface
+@preconcurrency import NeedleFoundation
import NoticeDomain
import NoticeDomainInterface
import StorageFeature
diff --git a/Projects/App/Sources/Application/AppComponent+Notification.swift b/Projects/App/Sources/Application/AppComponent+Notification.swift
index d3bcd78c9..d569ee84a 100644
--- a/Projects/App/Sources/Application/AppComponent+Notification.swift
+++ b/Projects/App/Sources/Application/AppComponent+Notification.swift
@@ -1,3 +1,4 @@
+@preconcurrency import NeedleFoundation
import NotificationDomain
import NotificationDomainInterface
diff --git a/Projects/App/Sources/Application/AppComponent+Playlist.swift b/Projects/App/Sources/Application/AppComponent+Playlist.swift
index cf39453fb..45928cc3b 100644
--- a/Projects/App/Sources/Application/AppComponent+Playlist.swift
+++ b/Projects/App/Sources/Application/AppComponent+Playlist.swift
@@ -2,6 +2,7 @@ import BaseFeature
import BaseFeatureInterface
import ImageDomain
import ImageDomainInterface
+@preconcurrency import NeedleFoundation
import PlaylistDomain
import PlaylistDomainInterface
import PlaylistFeature
diff --git a/Projects/App/Sources/Application/AppComponent+Price.swift b/Projects/App/Sources/Application/AppComponent+Price.swift
index 954208ac9..cf111f5b8 100644
--- a/Projects/App/Sources/Application/AppComponent+Price.swift
+++ b/Projects/App/Sources/Application/AppComponent+Price.swift
@@ -1,4 +1,5 @@
import Foundation
+@preconcurrency import NeedleFoundation
import PriceDomain
import PriceDomainInterface
diff --git a/Projects/App/Sources/Application/AppComponent+Search.swift b/Projects/App/Sources/Application/AppComponent+Search.swift
index 08e8f8c20..24ba0339d 100644
--- a/Projects/App/Sources/Application/AppComponent+Search.swift
+++ b/Projects/App/Sources/Application/AppComponent+Search.swift
@@ -1,4 +1,5 @@
import Foundation
+@preconcurrency import NeedleFoundation
import SearchDomain
import SearchDomainInterface
import SearchFeature
diff --git a/Projects/App/Sources/Application/AppComponent+Songs.swift b/Projects/App/Sources/Application/AppComponent+Songs.swift
index b0f65f952..efbf43daa 100644
--- a/Projects/App/Sources/Application/AppComponent+Songs.swift
+++ b/Projects/App/Sources/Application/AppComponent+Songs.swift
@@ -5,6 +5,7 @@ import LyricHighlightingFeature
import LyricHighlightingFeatureInterface
import MusicDetailFeature
import MusicDetailFeatureInterface
+@preconcurrency import NeedleFoundation
import SongsDomain
import SongsDomainInterface
diff --git a/Projects/App/Sources/Application/AppComponent+Storage.swift b/Projects/App/Sources/Application/AppComponent+Storage.swift
index c753e5741..a37f045bf 100644
--- a/Projects/App/Sources/Application/AppComponent+Storage.swift
+++ b/Projects/App/Sources/Application/AppComponent+Storage.swift
@@ -1,5 +1,6 @@
import BaseFeature
import BaseFeatureInterface
+@preconcurrency import NeedleFoundation
import StorageFeature
import StorageFeatureInterface
diff --git a/Projects/App/Sources/Application/AppComponent+Team.swift b/Projects/App/Sources/Application/AppComponent+Team.swift
index c5c05fd94..0ffd48627 100644
--- a/Projects/App/Sources/Application/AppComponent+Team.swift
+++ b/Projects/App/Sources/Application/AppComponent+Team.swift
@@ -1,3 +1,4 @@
+@preconcurrency import NeedleFoundation
import TeamDomain
import TeamDomainInterface
import TeamFeature
diff --git a/Projects/App/Sources/Application/AppComponent+User.swift b/Projects/App/Sources/Application/AppComponent+User.swift
index cdf8a4b02..c441eeeb8 100644
--- a/Projects/App/Sources/Application/AppComponent+User.swift
+++ b/Projects/App/Sources/Application/AppComponent+User.swift
@@ -1,4 +1,5 @@
import BaseFeature
+@preconcurrency import NeedleFoundation
import SignInFeature
import StorageFeature
import UserDomain
diff --git a/Projects/App/Sources/Application/AppComponent.swift b/Projects/App/Sources/Application/AppComponent.swift
index d0434b55b..676e6a772 100644
--- a/Projects/App/Sources/Application/AppComponent.swift
+++ b/Projects/App/Sources/Application/AppComponent.swift
@@ -3,16 +3,12 @@ import Foundation
import KeychainModule
import MainTabFeature
import MyInfoFeature
-import NeedleFoundation
+@preconcurrency import NeedleFoundation
import RootFeature
import StorageFeature
import UIKit
public final class AppComponent: BootstrapComponent {
- public func makeRootView() -> IntroViewController {
- rootComponent.makeView()
- }
-
public var keychain: any Keychain {
shared {
KeychainImpl()
diff --git a/Projects/App/Sources/Application/AppDelegate.swift b/Projects/App/Sources/Application/AppDelegate.swift
index 162350f4b..1934f640e 100644
--- a/Projects/App/Sources/Application/AppDelegate.swift
+++ b/Projects/App/Sources/Application/AppDelegate.swift
@@ -19,7 +19,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
) -> Bool {
// Use Firebase library to configure APIs
FirebaseApp.configure()
- if let userInfo = PreferenceManager.userInfo {
+ if let userInfo = PreferenceManager.shared.userInfo {
LogManager.setUserID(userID: userInfo.decryptedID)
} else {
LogManager.setUserID(userID: nil)
@@ -105,19 +105,19 @@ extension AppDelegate {
}
private func initializeUserProperty() {
- if let loginPlatform = PreferenceManager.userInfo?.platform {
+ if let loginPlatform = PreferenceManager.shared.userInfo?.platform {
LogManager.setUserProperty(property: .loginPlatform(platform: loginPlatform))
} else {
LogManager.clearUserProperty(property: .loginPlatform(platform: ""))
}
- if let fruitTotal = PreferenceManager.userInfo?.itemCount {
+ if let fruitTotal = PreferenceManager.shared.userInfo?.itemCount {
LogManager.setUserProperty(property: .fruitTotal(count: fruitTotal))
} else {
LogManager.clearUserProperty(property: .fruitTotal(count: -1))
}
- if let playPlatform = PreferenceManager.songPlayPlatformType {
+ if let playPlatform = PreferenceManager.shared.songPlayPlatformType {
LogManager.setUserProperty(property: .songPlayPlatform(platform: playPlatform.display))
}
diff --git a/Projects/App/Sources/Application/NeedleGenerated.swift b/Projects/App/Sources/Application/NeedleGenerated.swift
new file mode 100644
index 000000000..5a27e7e15
--- /dev/null
+++ b/Projects/App/Sources/Application/NeedleGenerated.swift
@@ -0,0 +1,2031 @@
+
+
+import AppDomain
+import AppDomainInterface
+import ArtistDomain
+import ArtistDomainInterface
+import ArtistFeature
+import ArtistFeatureInterface
+import AuthDomain
+import AuthDomainInterface
+import BaseDomainInterface
+import BaseFeature
+import BaseFeatureInterface
+import ChartDomain
+import ChartDomainInterface
+import ChartFeature
+import ChartFeatureInterface
+import CreditDomain
+import CreditDomainInterface
+import CreditSongListFeature
+import CreditSongListFeatureInterface
+import FaqDomain
+import FaqDomainInterface
+import Foundation
+import FruitDrawFeature
+import FruitDrawFeatureInterface
+import HomeFeature
+import HomeFeatureInterface
+import ImageDomain
+import ImageDomainInterface
+import KeychainModule
+import LikeDomain
+import LikeDomainInterface
+import LyricHighlightingFeature
+import LyricHighlightingFeatureInterface
+import MainTabFeature
+import MusicDetailFeature
+import MusicDetailFeatureInterface
+import MyInfoFeature
+import MyInfoFeatureInterface
+@preconcurrency import NeedleFoundation
+import NoticeDomain
+import NoticeDomainInterface
+import NotificationDomain
+import NotificationDomainInterface
+import PlaylistDomain
+import PlaylistDomainInterface
+import PlaylistFeature
+import PlaylistFeatureInterface
+import PriceDomain
+import PriceDomainInterface
+import RootFeature
+import SearchDomain
+import SearchDomainInterface
+import SearchFeature
+import SearchFeatureInterface
+import SignInFeature
+import SignInFeatureInterface
+import SongCreditFeature
+import SongCreditFeatureInterface
+import SongsDomain
+import SongsDomainInterface
+import StorageFeature
+import StorageFeatureInterface
+import TeamDomain
+import TeamDomainInterface
+import TeamFeature
+import TeamFeatureInterface
+import UIKit
+import UserDomain
+import UserDomainInterface
+
+// swiftlint:disable unused_declaration
+private let needleDependenciesHash : String? = nil
+
+// MARK: - Traversal Helpers
+
+private func parent1(_ component: NeedleFoundation.Scope) -> NeedleFoundation.Scope {
+ return component.parent
+}
+
+// MARK: - Providers
+
+#if !NEEDLE_DYNAMIC
+
+@MainActor private class ArtistDependency132a213bf62ad60c622cProvider: @preconcurrency ArtistDependency {
+ var fetchArtistListUseCase: any FetchArtistListUseCase {
+ return appComponent.fetchArtistListUseCase
+ }
+ var artistDetailFactory: any ArtistDetailFactory {
+ return appComponent.artistDetailFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ArtistComponent
+@MainActor private func factorye0c5444f5894148bdd93f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ArtistDependency132a213bf62ad60c622cProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class ArtistDetailDependencyee413dcf7a70e89df6d9Provider: @preconcurrency ArtistDetailDependency {
+ var artistMusicComponent: ArtistMusicComponent {
+ return appComponent.artistMusicComponent
+ }
+ var fetchArtistDetailUseCase: any FetchArtistDetailUseCase {
+ return appComponent.fetchArtistDetailUseCase
+ }
+ var fetchArtistSubscriptionStatusUseCase: any FetchArtistSubscriptionStatusUseCase {
+ return appComponent.fetchArtistSubscriptionStatusUseCase
+ }
+ var subscriptionArtistUseCase: any SubscriptionArtistUseCase {
+ return appComponent.subscriptionArtistUseCase
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ArtistDetailComponent
+@MainActor private func factory35314797fadaf164ece6f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ArtistDetailDependencyee413dcf7a70e89df6d9Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class ArtistMusicContentDependency1615ac8469e54ec51921Provider: @preconcurrency ArtistMusicContentDependency {
+ var fetchArtistSongListUseCase: any FetchArtistSongListUseCase {
+ return appComponent.fetchArtistSongListUseCase
+ }
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ArtistMusicContentComponent
+@MainActor private func factory8b6ffa46033e2529b5daf47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ArtistMusicContentDependency1615ac8469e54ec51921Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class ArtistMusicDependencya0f5073287829dfbc260Provider: @preconcurrency ArtistMusicDependency {
+ var artistMusicContentComponent: ArtistMusicContentComponent {
+ return appComponent.artistMusicContentComponent
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ArtistMusicComponent
+@MainActor private func factory382e7f8466df35a3f1d9f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ArtistMusicDependencya0f5073287829dfbc260Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class LyricHighlightingDependency47c68b56cdde819901d2Provider: @preconcurrency LyricHighlightingDependency {
+ var fetchLyricsUseCase: any FetchLyricsUseCase {
+ return appComponent.fetchLyricsUseCase
+ }
+ var lyricDecoratingComponent: LyricDecoratingComponent {
+ return appComponent.lyricDecoratingComponent
+ }
+ var lyricHighlightingFactory: any LyricHighlightingFactory {
+ return appComponent.lyricHighlightingFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->LyricHighlightingComponent
+@MainActor private func factory57ee59e468bef412b173f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return LyricHighlightingDependency47c68b56cdde819901d2Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class LyricDecoratingDependencya7e8bf6f2f4ae447ba4eProvider: @preconcurrency LyricDecoratingDependency {
+ var fetchLyricDecoratingBackgroundUseCase: any FetchLyricDecoratingBackgroundUseCase {
+ return appComponent.fetchLyricDecoratingBackgroundUseCase
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->LyricDecoratingComponent
+@MainActor private func factory5d05db9eb4337d682097f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return LyricDecoratingDependencya7e8bf6f2f4ae447ba4eProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class MainTabBarDependencycd05b79389a6a7a6c20fProvider: @preconcurrency MainTabBarDependency {
+ var fetchNoticePopupUseCase: any FetchNoticePopupUseCase {
+ return appComponent.fetchNoticePopupUseCase
+ }
+ var fetchNoticeIDListUseCase: any FetchNoticeIDListUseCase {
+ return appComponent.fetchNoticeIDListUseCase
+ }
+ var updateNotificationTokenUseCase: any UpdateNotificationTokenUseCase {
+ return appComponent.updateNotificationTokenUseCase
+ }
+ var fetchSongUseCase: any FetchSongUseCase {
+ return appComponent.fetchSongUseCase
+ }
+ var appEntryState: any AppEntryStateHandleable {
+ return appComponent.appEntryState
+ }
+ var homeFactory: any HomeFactory {
+ return appComponent.homeFactory
+ }
+ var searchFactory: any SearchFactory {
+ return appComponent.searchFactory
+ }
+ var artistFactory: any ArtistFactory {
+ return appComponent.artistFactory
+ }
+ var storageFactory: any StorageFactory {
+ return appComponent.storageFactory
+ }
+ var myInfoFactory: any MyInfoFactory {
+ return appComponent.myInfoFactory
+ }
+ var noticePopupComponent: NoticePopupComponent {
+ return appComponent.noticePopupComponent
+ }
+ var noticeDetailFactory: any NoticeDetailFactory {
+ return appComponent.noticeDetailFactory
+ }
+ var playlistDetailFactory: any PlaylistDetailFactory {
+ return appComponent.playlistDetailFactory
+ }
+ var musicDetailFactory: any MusicDetailFactory {
+ return appComponent.musicDetailFactory
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->MainTabBarComponent
+@MainActor private func factorye547a52b3fce5887c8c7f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return MainTabBarDependencycd05b79389a6a7a6c20fProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class BottomTabBarDependency237c2bd1c7be62020295Provider: @preconcurrency BottomTabBarDependency {
+
+
+ init() {
+
+ }
+}
+/// ^->AppComponent->BottomTabBarComponent
+@MainActor private func factoryd34fa9e493604a6295bde3b0c44298fc1c149afb(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return BottomTabBarDependency237c2bd1c7be62020295Provider()
+}
+@MainActor private class MainContainerDependencyd9d908a1d0cf8937bbadProvider: @preconcurrency MainContainerDependency {
+ var bottomTabBarComponent: BottomTabBarComponent {
+ return appComponent.bottomTabBarComponent
+ }
+ var mainTabBarComponent: MainTabBarComponent {
+ return appComponent.mainTabBarComponent
+ }
+ var playlistFactory: any PlaylistFactory {
+ return appComponent.playlistFactory
+ }
+ var playlistPresenterGlobalState: any PlayListPresenterGlobalStateProtocol {
+ return appComponent.playlistPresenterGlobalState
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->MainContainerComponent
+@MainActor private func factory8e19f48d5d573d3ea539f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return MainContainerDependencyd9d908a1d0cf8937bbadProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class NoticePopupDependency579e3504f53119c2eef1Provider: @preconcurrency NoticePopupDependency {
+
+
+ init() {
+
+ }
+}
+/// ^->AppComponent->NoticePopupComponent
+@MainActor private func factorycd081aacb61d6a707ca7e3b0c44298fc1c149afb(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return NoticePopupDependency579e3504f53119c2eef1Provider()
+}
+@MainActor private class PlaylistCoverOptionPopupDependencydda632c1d493aaca2ef1Provider: @preconcurrency PlaylistCoverOptionPopupDependency {
+ var fetchPlaylistImagePriceUseCase: any FetchPlaylistImagePriceUseCase {
+ return appComponent.fetchPlaylistImagePriceUseCase
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->PlaylistCoverOptionPopupComponent
+@MainActor private func factory487946b77daee32980aff47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return PlaylistCoverOptionPopupDependencydda632c1d493aaca2ef1Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class PlaylistDetailFactoryDependencyad39fd621b86af45813fProvider: @preconcurrency PlaylistDetailFactoryDependency {
+ var myPlaylistDetailFactory: any MyPlaylistDetailFactory {
+ return appComponent.myPlaylistDetailFactory
+ }
+ var unknownPlaylistDetailFactory: any UnknownPlaylistDetailFactory {
+ return appComponent.unknownPlaylistDetailFactory
+ }
+ var wakmusicPlaylistDetailFactory: any WakmusicPlaylistDetailFactory {
+ return appComponent.wakmusicPlaylistDetailFactory
+ }
+ var requestPlaylistOwnerIDUsecase: any RequestPlaylistOwnerIDUsecase {
+ return appComponent.requestPlaylistOwnerIDUsecase
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->PlaylistDetailComponent
+@MainActor private func factory6595408565b754d9f0f7f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return PlaylistDetailFactoryDependencyad39fd621b86af45813fProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class WakmusicPlaylistDetailDependencyaf7bde55d9c36b36ed3cProvider: @preconcurrency WakmusicPlaylistDetailDependency {
+ var fetchWMPlaylistDetailUseCase: any FetchWMPlaylistDetailUseCase {
+ return appComponent.fetchWMPlaylistDetailUseCase
+ }
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->WakmusicPlaylistDetailComponent
+@MainActor private func factorye3e053cabf65749566c8f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return WakmusicPlaylistDetailDependencyaf7bde55d9c36b36ed3cProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class MyPlaylistDetailDependency69ff6bac42b1db843b34Provider: @preconcurrency MyPlaylistDetailDependency {
+ var fetchPlaylistDetailUseCase: any FetchPlaylistDetailUseCase {
+ return appComponent.fetchPlaylistDetailUseCase
+ }
+ var updatePlaylistUseCase: any UpdatePlaylistUseCase {
+ return appComponent.updatePlaylistUseCase
+ }
+ var updateTitleAndPrivateUseCase: any UpdateTitleAndPrivateUseCase {
+ return appComponent.updateTitleAndPrivateUseCase
+ }
+ var removeSongsUseCase: any RemoveSongsUseCase {
+ return appComponent.removeSongsUseCase
+ }
+ var uploadDefaultPlaylistImageUseCase: any UploadDefaultPlaylistImageUseCase {
+ return appComponent.uploadDefaultPlaylistImageUseCase
+ }
+ var logoutUseCase: any LogoutUseCase {
+ return appComponent.logoutUseCase
+ }
+ var multiPurposePopupFactory: any MultiPurposePopupFactory {
+ return appComponent.multiPurposePopupFactory
+ }
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var playlistCoverOptionPopupFactory: any PlaylistCoverOptionPopupFactory {
+ return appComponent.playlistCoverOptionPopupFactory
+ }
+ var checkPlaylistCoverFactory: any CheckPlaylistCoverFactory {
+ return appComponent.checkPlaylistCoverFactory
+ }
+ var defaultPlaylistCoverFactory: any DefaultPlaylistCoverFactory {
+ return appComponent.defaultPlaylistCoverFactory
+ }
+ var requestCustomImageURLUseCase: any RequestCustomImageURLUseCase {
+ return appComponent.requestCustomImageURLUseCase
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->MyPlaylistDetailComponent
+@MainActor private func factoryc6efd92ea498eaae7ff8f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return MyPlaylistDetailDependency69ff6bac42b1db843b34Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class DefaultPlaylistCoverDependency47d3a4d69f35b248b60dProvider: @preconcurrency DefaultPlaylistCoverDependency {
+ var fetchDefaultPlaylistImageUseCase: any FetchDefaultPlaylistImageUseCase {
+ return appComponent.fetchDefaultPlaylistImageUseCase
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->DefaultPlaylistCoverComponent
+@MainActor private func factory89371387a9e4c131e13df47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return DefaultPlaylistCoverDependency47d3a4d69f35b248b60dProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class PlaylistDependency6f376d117dc0f38671edProvider: @preconcurrency PlaylistDependency {
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->PlaylistComponent
+@MainActor private func factory3a0a6eb1061d8d5a2deff47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return PlaylistDependency6f376d117dc0f38671edProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class UnknownPlaylistDetailDependency7288879231117fbf1b1bProvider: @preconcurrency UnknownPlaylistDetailDependency {
+ var fetchPlaylistDetailUseCase: any FetchPlaylistDetailUseCase {
+ return appComponent.fetchPlaylistDetailUseCase
+ }
+ var subscribePlaylistUseCase: any SubscribePlaylistUseCase {
+ return appComponent.subscribePlaylistUseCase
+ }
+ var checkSubscriptionUseCase: any CheckSubscriptionUseCase {
+ return appComponent.checkSubscriptionUseCase
+ }
+ var logoutUseCase: any LogoutUseCase {
+ return appComponent.logoutUseCase
+ }
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->UnknownPlaylistDetailComponent
+@MainActor private func factorya6d30d5b4471815dceb2f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return UnknownPlaylistDetailDependency7288879231117fbf1b1bProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class CheckPlaylistCoverDependency8efc6117f6bae3f05ffdProvider: @preconcurrency CheckPlaylistCoverDependency {
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->CheckPlaylistCoverComponent
+@MainActor private func factory025ce9f6d91409a9f719f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return CheckPlaylistCoverDependency8efc6117f6bae3f05ffdProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class FruitStorageDependencybef279261018fd1c1669Provider: @preconcurrency FruitStorageDependency {
+ var fetchFruitListUseCase: any FetchFruitListUseCase {
+ return appComponent.fetchFruitListUseCase
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->FruitStorageComponent
+@MainActor private func factory070e42b0224381c8cdf4f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return FruitStorageDependencybef279261018fd1c1669Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class FruitDrawDependency55f36ae08a622ad39d3fProvider: @preconcurrency FruitDrawDependency {
+ var fetchFruitDrawStatusUseCase: any FetchFruitDrawStatusUseCase {
+ return appComponent.fetchFruitDrawStatusUseCase
+ }
+ var drawFruitUseCase: any DrawFruitUseCase {
+ return appComponent.drawFruitUseCase
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->FruitDrawComponent
+@MainActor private func factoryc603eb682d7a111dc261f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return FruitDrawDependency55f36ae08a622ad39d3fProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class CreditSongListTabItemDependency454e93d0f00e09bca0b5Provider: @preconcurrency CreditSongListTabItemDependency {
+ var fetchCreditSongListUseCase: any FetchCreditSongListUseCase {
+ return appComponent.fetchCreditSongListUseCase
+ }
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->CreditSongListTabItemComponent
+@MainActor private func factory95828465b02bfed94ec5f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return CreditSongListTabItemDependency454e93d0f00e09bca0b5Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class CreditSongListTabDependencybdb2c08847a72c255a37Provider: @preconcurrency CreditSongListTabDependency {
+ var creditSongListTabItemFactory: any CreditSongListTabItemFactory {
+ return appComponent.creditSongListTabItemFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->CreditSongListTabComponent
+@MainActor private func factory85beabbf7f1f193dec41f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return CreditSongListTabDependencybdb2c08847a72c255a37Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class CreditSongListDependencye5d029d068347ee34e68Provider: @preconcurrency CreditSongListDependency {
+ var creditSongListTabFactory: any CreditSongListTabFactory {
+ return appComponent.creditSongListTabFactory
+ }
+ var fetchCreditProfileUseCase: any FetchCreditProfileUseCase {
+ return appComponent.fetchCreditProfileUseCase
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->CreditSongListComponent
+@MainActor private func factorye0caf4db37d0954ab34ef47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return CreditSongListDependencye5d029d068347ee34e68Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class ChartDependencyafd8882010751c9ef054Provider: @preconcurrency ChartDependency {
+ var chartContentComponent: ChartContentComponent {
+ return appComponent.chartContentComponent
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ChartComponent
+@MainActor private func factoryeac6a4df54bbd391d31bf47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ChartDependencyafd8882010751c9ef054Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class ChartContentDependency3b8e41cfba060e4d16caProvider: @preconcurrency ChartContentDependency {
+ var fetchChartRankingUseCase: any FetchChartRankingUseCase {
+ return appComponent.fetchChartRankingUseCase
+ }
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ChartContentComponent
+@MainActor private func factoryc9a137630ce76907f36ff47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ChartContentDependency3b8e41cfba060e4d16caProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class TeamInfoDependency94c25b4e5acfbc37741cProvider: @preconcurrency TeamInfoDependency {
+ var fetchTeamListUseCase: any FetchTeamListUseCase {
+ return appComponent.fetchTeamListUseCase
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->TeamInfoComponent
+@MainActor private func factorybe60e92b5190e00abf41f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return TeamInfoDependency94c25b4e5acfbc37741cProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class StorageDependency1447167c38e97ef97427Provider: @preconcurrency StorageDependency {
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var multiPurposePopupFactory: any MultiPurposePopupFactory {
+ return appComponent.multiPurposePopupFactory
+ }
+ var listStorageComponent: ListStorageComponent {
+ return appComponent.listStorageComponent
+ }
+ var likeStorageComponent: LikeStorageComponent {
+ return appComponent.likeStorageComponent
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->StorageComponent
+@MainActor private func factory2415399d25299b97b98bf47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return StorageDependency1447167c38e97ef97427Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class ListStorageDependency77e3806cde238dfa4bf2Provider: @preconcurrency ListStorageDependency {
+ var multiPurposePopupFactory: any MultiPurposePopupFactory {
+ return appComponent.multiPurposePopupFactory
+ }
+ var playlistDetailFactory: any PlaylistDetailFactory {
+ return appComponent.playlistDetailFactory
+ }
+ var createPlaylistUseCase: any CreatePlaylistUseCase {
+ return appComponent.createPlaylistUseCase
+ }
+ var editPlayListOrderUseCase: any EditPlaylistOrderUseCase {
+ return appComponent.editPlayListOrderUseCase
+ }
+ var fetchPlayListUseCase: any FetchPlaylistUseCase {
+ return appComponent.fetchPlayListUseCase
+ }
+ var deletePlayListUseCase: any DeletePlaylistUseCase {
+ return appComponent.deletePlayListUseCase
+ }
+ var fetchPlaylistSongsUseCase: any FetchPlaylistSongsUseCase {
+ return appComponent.fetchPlaylistSongsUseCase
+ }
+ var fetchPlaylistCreationPriceUseCase: any FetchPlaylistCreationPriceUseCase {
+ return appComponent.fetchPlaylistCreationPriceUseCase
+ }
+ var logoutUseCase: any LogoutUseCase {
+ return appComponent.logoutUseCase
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var fruitDrawFactory: any FruitDrawFactory {
+ return appComponent.fruitDrawFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ListStorageComponent
+@MainActor private func factory75c66cb7534f04d45951f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ListStorageDependency77e3806cde238dfa4bf2Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class LikeStorageDependency00a252a1ff3ab6e82ceeProvider: @preconcurrency LikeStorageDependency {
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var fetchFavoriteSongsUseCase: any FetchFavoriteSongsUseCase {
+ return appComponent.fetchFavoriteSongsUseCase
+ }
+ var editFavoriteSongsOrderUseCase: any EditFavoriteSongsOrderUseCase {
+ return appComponent.editFavoriteSongsOrderUseCase
+ }
+ var deleteFavoriteListUseCase: any DeleteFavoriteListUseCase {
+ return appComponent.deleteFavoriteListUseCase
+ }
+ var logoutUseCase: any LogoutUseCase {
+ return appComponent.logoutUseCase
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->LikeStorageComponent
+@MainActor private func factory9f7222d7c56236b2e993f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return LikeStorageDependency00a252a1ff3ab6e82ceeProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class RootDependency3944cc797a4a88956fb5Provider: @preconcurrency RootDependency {
+ var mainContainerComponent: MainContainerComponent {
+ return appComponent.mainContainerComponent
+ }
+ var permissionComponent: PermissionComponent {
+ return appComponent.permissionComponent
+ }
+ var fetchUserInfoUseCase: any FetchUserInfoUseCase {
+ return appComponent.fetchUserInfoUseCase
+ }
+ var fetchAppCheckUseCase: any FetchAppCheckUseCase {
+ return appComponent.fetchAppCheckUseCase
+ }
+ var logoutUseCase: any LogoutUseCase {
+ return appComponent.logoutUseCase
+ }
+ var checkIsExistAccessTokenUseCase: any CheckIsExistAccessTokenUseCase {
+ return appComponent.checkIsExistAccessTokenUseCase
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->RootComponent
+@MainActor private func factory264bfc4d4cb6b0629b40f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return RootDependency3944cc797a4a88956fb5Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class PermissionDependency517ed7598d8c08817d14Provider: @preconcurrency PermissionDependency {
+
+
+ init() {
+
+ }
+}
+/// ^->AppComponent->PermissionComponent
+@MainActor private func factoryc1d4d80afbccf86bf1c0e3b0c44298fc1c149afb(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return PermissionDependency517ed7598d8c08817d14Provider()
+}
+@MainActor private class SignInDependency5dda0dd015447272446cProvider: @preconcurrency SignInDependency {
+ var fetchTokenUseCase: any FetchTokenUseCase {
+ return appComponent.fetchTokenUseCase
+ }
+ var fetchUserInfoUseCase: any FetchUserInfoUseCase {
+ return appComponent.fetchUserInfoUseCase
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->SignInComponent
+@MainActor private func factoryda2925fd76da866a652af47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return SignInDependency5dda0dd015447272446cProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class NewSongsDependencyee634cc0cae21fc2a9e3Provider: @preconcurrency NewSongsDependency {
+ var newSongsContentComponent: NewSongsContentComponent {
+ return appComponent.newSongsContentComponent
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->NewSongsComponent
+@MainActor private func factory379179b05dd24ff979edf47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return NewSongsDependencyee634cc0cae21fc2a9e3Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class HomeDependency443c4e1871277bd8432aProvider: @preconcurrency HomeDependency {
+ var fetchChartRankingUseCase: any FetchChartRankingUseCase {
+ return appComponent.fetchChartRankingUseCase
+ }
+ var fetchNewSongsUseCase: any FetchNewSongsUseCase {
+ return appComponent.fetchNewSongsUseCase
+ }
+ var fetchRecommendPlaylistUseCase: any FetchRecommendPlaylistUseCase {
+ return appComponent.fetchRecommendPlaylistUseCase
+ }
+ var playlistDetailFactory: any PlaylistDetailFactory {
+ return appComponent.playlistDetailFactory
+ }
+ var chartFactory: any ChartFactory {
+ return appComponent.chartFactory
+ }
+ var newSongsComponent: NewSongsComponent {
+ return appComponent.newSongsComponent
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->HomeComponent
+@MainActor private func factory67229cdf0f755562b2b1f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return HomeDependency443c4e1871277bd8432aProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class NewSongsContentDependency93a05f20fa300c5bbec3Provider: @preconcurrency NewSongsContentDependency {
+ var fetchNewSongsUseCase: any FetchNewSongsUseCase {
+ return appComponent.fetchNewSongsUseCase
+ }
+ var fetchNewSongsPlaylistUseCase: any FetchNewSongsPlaylistUseCase {
+ return appComponent.fetchNewSongsPlaylistUseCase
+ }
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->NewSongsContentComponent
+@MainActor private func factorye130e1fbfcbc622a4c38f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return NewSongsContentDependency93a05f20fa300c5bbec3Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class WakmusicRecommendDependency7d2e1de16b5802ae90ceProvider: @preconcurrency WakmusicRecommendDependency {
+ var fetchRecommendPlaylistUseCase: any FetchRecommendPlaylistUseCase {
+ return appComponent.fetchRecommendPlaylistUseCase
+ }
+ var wakmusicPlaylistDetailFactory: any WakmusicPlaylistDetailFactory {
+ return appComponent.wakmusicPlaylistDetailFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->WakmusicRecommendComponent
+@MainActor private func factoryaf1c3535530356714983f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return WakmusicRecommendDependency7d2e1de16b5802ae90ceProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class BeforeSearchDependencyebdecb1d478a4766488dProvider: @preconcurrency BeforeSearchDependency {
+ var fetchRecommendPlaylistUseCase: any FetchRecommendPlaylistUseCase {
+ return appComponent.fetchRecommendPlaylistUseCase
+ }
+ var fetchCurrentVideoUseCase: any FetchCurrentVideoUseCase {
+ return appComponent.fetchCurrentVideoUseCase
+ }
+ var wakmusicRecommendComponent: WakmusicRecommendComponent {
+ return appComponent.wakmusicRecommendComponent
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var playlistDetailFactory: any PlaylistDetailFactory {
+ return appComponent.playlistDetailFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->BeforeSearchComponent
+@MainActor private func factory9bb852337d5550979293f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return BeforeSearchDependencyebdecb1d478a4766488dProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class SearchDependencya86903a2c751a4f762e8Provider: @preconcurrency SearchDependency {
+ var beforeSearchComponent: BeforeSearchComponent {
+ return appComponent.beforeSearchComponent
+ }
+ var afterSearchComponent: AfterSearchComponent {
+ return appComponent.afterSearchComponent
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var searchGlobalScrollState: any SearchGlobalScrollProtocol {
+ return appComponent.searchGlobalScrollState
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->SearchComponent
+@MainActor private func factorye3d049458b2ccbbcb3b6f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return SearchDependencya86903a2c751a4f762e8Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class AfterSearchDependency61822c19bc2eb46d7c52Provider: @preconcurrency AfterSearchDependency {
+ var songSearchResultFactory: any SongSearchResultFactory {
+ return appComponent.songSearchResultFactory
+ }
+ var listSearchResultFactory: any ListSearchResultFactory {
+ return appComponent.listSearchResultFactory
+ }
+ var searchGlobalScrollState: any SearchGlobalScrollProtocol {
+ return appComponent.searchGlobalScrollState
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->AfterSearchComponent
+@MainActor private func factoryeb2da679e35e2c4fb9a5f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return AfterSearchDependency61822c19bc2eb46d7c52Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class ListSearchResultDependencyd64afa403e14dc980d2fProvider: @preconcurrency ListSearchResultDependency {
+ var fetchSearchPlaylistsUseCase: any FetchSearchPlaylistsUseCase {
+ return appComponent.fetchSearchPlaylistsUseCase
+ }
+ var searchSortOptionComponent: SearchSortOptionComponent {
+ return appComponent.searchSortOptionComponent
+ }
+ var playlistDetailFactory: any PlaylistDetailFactory {
+ return appComponent.playlistDetailFactory
+ }
+ var searchGlobalScrollState: any SearchGlobalScrollProtocol {
+ return appComponent.searchGlobalScrollState
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ListSearchResultComponent
+@MainActor private func factory2c8e2a50d1fcf9efc9f8f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ListSearchResultDependencyd64afa403e14dc980d2fProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class SongSearchResultDependency7224c47222c188cd3de5Provider: @preconcurrency SongSearchResultDependency {
+ var fetchSearchSongsUseCase: any FetchSearchSongsUseCase {
+ return appComponent.fetchSearchSongsUseCase
+ }
+ var searchSortOptionComponent: SearchSortOptionComponent {
+ return appComponent.searchSortOptionComponent
+ }
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var searchGlobalScrollState: any SearchGlobalScrollProtocol {
+ return appComponent.searchGlobalScrollState
+ }
+ var songDetailPresenter: any SongDetailPresentable {
+ return appComponent.songDetailPresenter
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->SongSearchResultComponent
+@MainActor private func factory182af2382ca6172f89c1f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return SongSearchResultDependency7224c47222c188cd3de5Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class ContainSongsDependencydbd9ae8a072db3a22630Provider: @preconcurrency ContainSongsDependency {
+ var multiPurposePopupFactory: any MultiPurposePopupFactory {
+ return appComponent.multiPurposePopupFactory
+ }
+ var fetchPlayListUseCase: any FetchPlaylistUseCase {
+ return appComponent.fetchPlayListUseCase
+ }
+ var addSongIntoPlaylistUseCase: any AddSongIntoPlaylistUseCase {
+ return appComponent.addSongIntoPlaylistUseCase
+ }
+ var createPlaylistUseCase: any CreatePlaylistUseCase {
+ return appComponent.createPlaylistUseCase
+ }
+ var fetchPlaylistCreationPriceUseCase: any FetchPlaylistCreationPriceUseCase {
+ return appComponent.fetchPlaylistCreationPriceUseCase
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var logoutUseCase: any LogoutUseCase {
+ return appComponent.logoutUseCase
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ContainSongsComponent
+@MainActor private func factory4d4f4455414271fee232f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ContainSongsDependencydbd9ae8a072db3a22630Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class ServiceTermsDependencyd07df8dc0771e5580b47Provider: @preconcurrency ServiceTermsDependency {
+
+
+ init() {
+
+ }
+}
+/// ^->AppComponent->ServiceTermsComponent
+@MainActor private func factory8014909e2d8dba4e4f20e3b0c44298fc1c149afb(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ServiceTermsDependencyd07df8dc0771e5580b47Provider()
+}
+@MainActor private class PrivacyDependency51c6df0186843bf53e9cProvider: @preconcurrency PrivacyDependency {
+
+
+ init() {
+
+ }
+}
+/// ^->AppComponent->PrivacyComponent
+@MainActor private func factorye7f5d59533cfdd1614b0e3b0c44298fc1c149afb(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return PrivacyDependency51c6df0186843bf53e9cProvider()
+}
+@MainActor private class ServiceInfoDependency17ccca17be0fc87c9a2eProvider: @preconcurrency ServiceInfoDependency {
+ var openSourceLicenseFactory: any OpenSourceLicenseFactory {
+ return appComponent.openSourceLicenseFactory
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ServiceInfoComponent
+@MainActor private func factory3afd170b9974b0dbd863f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ServiceInfoDependency17ccca17be0fc87c9a2eProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class FaqDependency899aad15f17210a3af31Provider: @preconcurrency FaqDependency {
+ var faqContentFactory: any FaqContentFactory {
+ return appComponent.faqContentFactory
+ }
+ var fetchFaqCategoriesUseCase: any FetchFaqCategoriesUseCase {
+ return appComponent.fetchFaqCategoriesUseCase
+ }
+ var fetchFaqUseCase: any FetchFaqUseCase {
+ return appComponent.fetchFaqUseCase
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->FaqComponent
+@MainActor private func factory4e13cc6545633ffc2ed5f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return FaqDependency899aad15f17210a3af31Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class QuestionDependencyf7010567c2d88e76d191Provider: @preconcurrency QuestionDependency {
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->QuestionComponent
+@MainActor private func factoryedad1813a36115eec11ef47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return QuestionDependencyf7010567c2d88e76d191Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class MyInfoDependency3b44bce00dab6fc2e345Provider: @preconcurrency MyInfoDependency {
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var multiPurposePopupFactory: any MultiPurposePopupFactory {
+ return appComponent.multiPurposePopupFactory
+ }
+ var faqFactory: any FaqFactory {
+ return appComponent.faqFactory
+ }
+ var noticeFactory: any NoticeFactory {
+ return appComponent.noticeFactory
+ }
+ var questionFactory: any QuestionFactory {
+ return appComponent.questionFactory
+ }
+ var teamInfoFactory: any TeamInfoFactory {
+ return appComponent.teamInfoFactory
+ }
+ var settingFactory: any SettingFactory {
+ return appComponent.settingFactory
+ }
+ var profilePopupFactory: any ProfilePopupFactory {
+ return appComponent.profilePopupFactory
+ }
+ var fruitDrawFactory: any FruitDrawFactory {
+ return appComponent.fruitDrawFactory
+ }
+ var fruitStorageFactory: any FruitStorageFactory {
+ return appComponent.fruitStorageFactory
+ }
+ var fetchNoticeIDListUseCase: any FetchNoticeIDListUseCase {
+ return appComponent.fetchNoticeIDListUseCase
+ }
+ var setUserNameUseCase: any SetUserNameUseCase {
+ return appComponent.setUserNameUseCase
+ }
+ var fetchUserInfoUseCase: any FetchUserInfoUseCase {
+ return appComponent.fetchUserInfoUseCase
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->MyInfoComponent
+@MainActor private func factoryec2cede3edc2a626b35df47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return MyInfoDependency3b44bce00dab6fc2e345Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class SettingDependency792c9caceb5cb097fbecProvider: @preconcurrency SettingDependency {
+ var withdrawUserInfoUseCase: any WithdrawUserInfoUseCase {
+ return appComponent.withdrawUserInfoUseCase
+ }
+ var logoutUseCase: any LogoutUseCase {
+ return appComponent.logoutUseCase
+ }
+ var updateNotificationTokenUseCase: any UpdateNotificationTokenUseCase {
+ return appComponent.updateNotificationTokenUseCase
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var serviceTermsFactory: any ServiceTermFactory {
+ return appComponent.serviceTermsFactory
+ }
+ var privacyFactory: any PrivacyFactory {
+ return appComponent.privacyFactory
+ }
+ var openSourceLicenseFactory: any OpenSourceLicenseFactory {
+ return appComponent.openSourceLicenseFactory
+ }
+ var playTypeTogglePopupFactory: any PlayTypeTogglePopupFactory {
+ return appComponent.playTypeTogglePopupFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->SettingComponent
+@MainActor private func factoryee0bbc0b920a7007e1a9f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return SettingDependency792c9caceb5cb097fbecProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class NoticeDetailDependency714af3aed40eaebda420Provider: @preconcurrency NoticeDetailDependency {
+
+
+ init() {
+
+ }
+}
+/// ^->AppComponent->NoticeDetailComponent
+@MainActor private func factory3db143c2f80d621d5a7fe3b0c44298fc1c149afb(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return NoticeDetailDependency714af3aed40eaebda420Provider()
+}
+@MainActor private class ProfilePopupDependency3d548bc7afc8d2b8f092Provider: @preconcurrency ProfilePopupDependency {
+ var fetchProfileListUseCase: any FetchProfileListUseCase {
+ return appComponent.fetchProfileListUseCase
+ }
+ var setProfileUseCase: any SetProfileUseCase {
+ return appComponent.setProfileUseCase
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->ProfilePopupComponent
+@MainActor private func factory3a1ad3396729bed7200ef47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return ProfilePopupDependency3d548bc7afc8d2b8f092Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class OpenSourceLicenseDependencyb6842dcc36b26380b91aProvider: @preconcurrency OpenSourceLicenseDependency {
+
+
+ init() {
+
+ }
+}
+/// ^->AppComponent->OpenSourceLicenseComponent
+@MainActor private func factoryd505894818021731340ae3b0c44298fc1c149afb(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return OpenSourceLicenseDependencyb6842dcc36b26380b91aProvider()
+}
+@MainActor private class NoticeDependencyaec92ef53617a421bdf3Provider: @preconcurrency NoticeDependency {
+ var fetchNoticeAllUseCase: any FetchNoticeAllUseCase {
+ return appComponent.fetchNoticeAllUseCase
+ }
+ var noticeDetailFactory: any NoticeDetailFactory {
+ return appComponent.noticeDetailFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->NoticeComponent
+@MainActor private func factoryaf8e5665e5b9217918f5f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return NoticeDependencyaec92ef53617a421bdf3Provider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class SongCreditDependency973cc2df82285f0722fcProvider: @preconcurrency SongCreditDependency {
+ var fetchSongCreditsUseCase: any FetchSongCreditsUseCase {
+ return appComponent.fetchSongCreditsUseCase
+ }
+ var creditSongListFactory: any CreditSongListFactory {
+ return appComponent.creditSongListFactory
+ }
+ var artistDetailFactory: any ArtistDetailFactory {
+ return appComponent.artistDetailFactory
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->SongCreditComponent
+@MainActor private func factoryd48a3e0e81529a27a02bf47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return SongCreditDependency973cc2df82285f0722fcProvider(appComponent: parent1(component) as! AppComponent)
+}
+@MainActor private class MusicDetailDependencyb872e53d21248eec044dProvider: @preconcurrency MusicDetailDependency {
+ var fetchSongUseCase: any FetchSongUseCase {
+ return appComponent.fetchSongUseCase
+ }
+ var lyricHighlightingFactory: any LyricHighlightingFactory {
+ return appComponent.lyricHighlightingFactory
+ }
+ var songCreditFactory: any SongCreditFactory {
+ return appComponent.songCreditFactory
+ }
+ var signInFactory: any SignInFactory {
+ return appComponent.signInFactory
+ }
+ var containSongsFactory: any ContainSongsFactory {
+ return appComponent.containSongsFactory
+ }
+ var karaokeFactory: any KaraokeFactory {
+ return appComponent.karaokeFactory
+ }
+ var textPopupFactory: any TextPopupFactory {
+ return appComponent.textPopupFactory
+ }
+ var artistDetailFactory: any ArtistDetailFactory {
+ return appComponent.artistDetailFactory
+ }
+ var playlistPresenterGlobalState: any PlayListPresenterGlobalStateProtocol {
+ return appComponent.playlistPresenterGlobalState
+ }
+ var addLikeSongUseCase: any AddLikeSongUseCase {
+ return appComponent.addLikeSongUseCase
+ }
+ var cancelLikeSongUseCase: any CancelLikeSongUseCase {
+ return appComponent.cancelLikeSongUseCase
+ }
+ var findArtistIDUseCase: any FindArtistIDUseCase {
+ return appComponent.findArtistIDUseCase
+ }
+ private let appComponent: AppComponent
+ init(appComponent: AppComponent) {
+ self.appComponent = appComponent
+ }
+}
+/// ^->AppComponent->MusicDetailComponent
+@MainActor private func factory84f307443e9a78802606f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return MusicDetailDependencyb872e53d21248eec044dProvider(appComponent: parent1(component) as! AppComponent)
+}
+
+#else
+@MainActor extension AppComponent: Registration {
+ public func registerItems() {
+
+ localTable["keychain-any Keychain"] = { [unowned self] in self.keychain as Any }
+ localTable["remoteImageDataSource-any RemoteImageDataSource"] = { [unowned self] in self.remoteImageDataSource as Any }
+ localTable["imageRepository-any ImageRepository"] = { [unowned self] in self.imageRepository as Any }
+ localTable["fetchLyricDecoratingBackgroundUseCase-any FetchLyricDecoratingBackgroundUseCase"] = { [unowned self] in self.fetchLyricDecoratingBackgroundUseCase as Any }
+ localTable["fetchProfileListUseCase-any FetchProfileListUseCase"] = { [unowned self] in self.fetchProfileListUseCase as Any }
+ localTable["fetchDefaultPlaylistImageUseCase-any FetchDefaultPlaylistImageUseCase"] = { [unowned self] in self.fetchDefaultPlaylistImageUseCase as Any }
+ localTable["songDetailPresenter-any SongDetailPresentable"] = { [unowned self] in self.songDetailPresenter as Any }
+ localTable["homeFactory-any HomeFactory"] = { [unowned self] in self.homeFactory as Any }
+ localTable["musicDetailFactory-any MusicDetailFactory"] = { [unowned self] in self.musicDetailFactory as Any }
+ localTable["karaokeFactory-any KaraokeFactory"] = { [unowned self] in self.karaokeFactory as Any }
+ localTable["newSongsComponent-NewSongsComponent"] = { [unowned self] in self.newSongsComponent as Any }
+ localTable["newSongsContentComponent-NewSongsContentComponent"] = { [unowned self] in self.newSongsContentComponent as Any }
+ localTable["lyricHighlightingFactory-any LyricHighlightingFactory"] = { [unowned self] in self.lyricHighlightingFactory as Any }
+ localTable["lyricDecoratingComponent-LyricDecoratingComponent"] = { [unowned self] in self.lyricDecoratingComponent as Any }
+ localTable["remoteSongsDataSource-any RemoteSongsDataSource"] = { [unowned self] in self.remoteSongsDataSource as Any }
+ localTable["songsRepository-any SongsRepository"] = { [unowned self] in self.songsRepository as Any }
+ localTable["fetchSongUseCase-any FetchSongUseCase"] = { [unowned self] in self.fetchSongUseCase as Any }
+ localTable["fetchLyricsUseCase-any FetchLyricsUseCase"] = { [unowned self] in self.fetchLyricsUseCase as Any }
+ localTable["fetchNewSongsUseCase-any FetchNewSongsUseCase"] = { [unowned self] in self.fetchNewSongsUseCase as Any }
+ localTable["fetchNewSongsPlaylistUseCase-any FetchNewSongsPlaylistUseCase"] = { [unowned self] in self.fetchNewSongsPlaylistUseCase as Any }
+ localTable["fetchSongCreditsUseCase-any FetchSongCreditsUseCase"] = { [unowned self] in self.fetchSongCreditsUseCase as Any }
+ localTable["remoteCreditDataSource-any RemoteCreditDataSource"] = { [unowned self] in self.remoteCreditDataSource as Any }
+ localTable["creditRepository-any CreditRepository"] = { [unowned self] in self.creditRepository as Any }
+ localTable["fetchCreditSongListUseCase-any FetchCreditSongListUseCase"] = { [unowned self] in self.fetchCreditSongListUseCase as Any }
+ localTable["fetchCreditProfileUseCase-any FetchCreditProfileUseCase"] = { [unowned self] in self.fetchCreditProfileUseCase as Any }
+ localTable["songCreditFactory-any SongCreditFactory"] = { [unowned self] in self.songCreditFactory as Any }
+ localTable["creditSongListFactory-any CreditSongListFactory"] = { [unowned self] in self.creditSongListFactory as Any }
+ localTable["creditSongListTabFactory-any CreditSongListTabFactory"] = { [unowned self] in self.creditSongListTabFactory as Any }
+ localTable["creditSongListTabItemFactory-any CreditSongListTabItemFactory"] = { [unowned self] in self.creditSongListTabItemFactory as Any }
+ localTable["remoteNotificationDataSource-any RemoteNotificationDataSource"] = { [unowned self] in self.remoteNotificationDataSource as Any }
+ localTable["notificationRepository-any NotificationRepository"] = { [unowned self] in self.notificationRepository as Any }
+ localTable["updateNotificationTokenUseCase-any UpdateNotificationTokenUseCase"] = { [unowned self] in self.updateNotificationTokenUseCase as Any }
+ localTable["signInFactory-any SignInFactory"] = { [unowned self] in self.signInFactory as Any }
+ localTable["localAuthDataSource-any LocalAuthDataSource"] = { [unowned self] in self.localAuthDataSource as Any }
+ localTable["remoteAuthDataSource-any RemoteAuthDataSource"] = { [unowned self] in self.remoteAuthDataSource as Any }
+ localTable["authRepository-any AuthRepository"] = { [unowned self] in self.authRepository as Any }
+ localTable["fetchTokenUseCase-any FetchTokenUseCase"] = { [unowned self] in self.fetchTokenUseCase as Any }
+ localTable["regenerateAccessTokenUseCase-any ReGenerateAccessTokenUseCase"] = { [unowned self] in self.regenerateAccessTokenUseCase as Any }
+ localTable["logoutUseCase-any LogoutUseCase"] = { [unowned self] in self.logoutUseCase as Any }
+ localTable["checkIsExistAccessTokenUseCase-any CheckIsExistAccessTokenUseCase"] = { [unowned self] in self.checkIsExistAccessTokenUseCase as Any }
+ localTable["remoteLikeDataSource-any RemoteLikeDataSource"] = { [unowned self] in self.remoteLikeDataSource as Any }
+ localTable["likeRepository-any LikeRepository"] = { [unowned self] in self.likeRepository as Any }
+ localTable["addLikeSongUseCase-any AddLikeSongUseCase"] = { [unowned self] in self.addLikeSongUseCase as Any }
+ localTable["cancelLikeSongUseCase-any CancelLikeSongUseCase"] = { [unowned self] in self.cancelLikeSongUseCase as Any }
+ localTable["playlistPresenterGlobalState-any PlayListPresenterGlobalStateProtocol"] = { [unowned self] in self.playlistPresenterGlobalState as Any }
+ localTable["playlistDetailFactory-any PlaylistDetailFactory"] = { [unowned self] in self.playlistDetailFactory as Any }
+ localTable["playlistFactory-any PlaylistFactory"] = { [unowned self] in self.playlistFactory as Any }
+ localTable["myPlaylistDetailFactory-any MyPlaylistDetailFactory"] = { [unowned self] in self.myPlaylistDetailFactory as Any }
+ localTable["unknownPlaylistDetailFactory-any UnknownPlaylistDetailFactory"] = { [unowned self] in self.unknownPlaylistDetailFactory as Any }
+ localTable["wakmusicPlaylistDetailFactory-any WakmusicPlaylistDetailFactory"] = { [unowned self] in self.wakmusicPlaylistDetailFactory as Any }
+ localTable["playlistCoverOptionPopupFactory-any PlaylistCoverOptionPopupFactory"] = { [unowned self] in self.playlistCoverOptionPopupFactory as Any }
+ localTable["checkPlaylistCoverFactory-any CheckPlaylistCoverFactory"] = { [unowned self] in self.checkPlaylistCoverFactory as Any }
+ localTable["defaultPlaylistCoverFactory-any DefaultPlaylistCoverFactory"] = { [unowned self] in self.defaultPlaylistCoverFactory as Any }
+ localTable["remotePlaylistDataSource-any RemotePlaylistDataSource"] = { [unowned self] in self.remotePlaylistDataSource as Any }
+ localTable["playlistRepository-any PlaylistRepository"] = { [unowned self] in self.playlistRepository as Any }
+ localTable["fetchRecommendPlaylistUseCase-any FetchRecommendPlaylistUseCase"] = { [unowned self] in self.fetchRecommendPlaylistUseCase as Any }
+ localTable["fetchPlaylistSongsUseCase-any FetchPlaylistSongsUseCase"] = { [unowned self] in self.fetchPlaylistSongsUseCase as Any }
+ localTable["fetchPlaylistDetailUseCase-any FetchPlaylistDetailUseCase"] = { [unowned self] in self.fetchPlaylistDetailUseCase as Any }
+ localTable["fetchWMPlaylistDetailUseCase-any FetchWMPlaylistDetailUseCase"] = { [unowned self] in self.fetchWMPlaylistDetailUseCase as Any }
+ localTable["createPlaylistUseCase-any CreatePlaylistUseCase"] = { [unowned self] in self.createPlaylistUseCase as Any }
+ localTable["updatePlaylistUseCase-any UpdatePlaylistUseCase"] = { [unowned self] in self.updatePlaylistUseCase as Any }
+ localTable["updateTitleAndPrivateUseCase-any UpdateTitleAndPrivateUseCase"] = { [unowned self] in self.updateTitleAndPrivateUseCase as Any }
+ localTable["addSongIntoPlaylistUseCase-any AddSongIntoPlaylistUseCase"] = { [unowned self] in self.addSongIntoPlaylistUseCase as Any }
+ localTable["removeSongsUseCase-any RemoveSongsUseCase"] = { [unowned self] in self.removeSongsUseCase as Any }
+ localTable["subscribePlaylistUseCase-any SubscribePlaylistUseCase"] = { [unowned self] in self.subscribePlaylistUseCase as Any }
+ localTable["checkSubscriptionUseCase-any CheckSubscriptionUseCase"] = { [unowned self] in self.checkSubscriptionUseCase as Any }
+ localTable["uploadDefaultPlaylistImageUseCase-any UploadDefaultPlaylistImageUseCase"] = { [unowned self] in self.uploadDefaultPlaylistImageUseCase as Any }
+ localTable["requestCustomImageURLUseCase-any RequestCustomImageURLUseCase"] = { [unowned self] in self.requestCustomImageURLUseCase as Any }
+ localTable["requestPlaylistOwnerIDUsecase-any RequestPlaylistOwnerIDUsecase"] = { [unowned self] in self.requestPlaylistOwnerIDUsecase as Any }
+ localTable["artistFactory-any ArtistFactory"] = { [unowned self] in self.artistFactory as Any }
+ localTable["remoteArtistDataSource-RemoteArtistDataSourceImpl"] = { [unowned self] in self.remoteArtistDataSource as Any }
+ localTable["artistRepository-any ArtistRepository"] = { [unowned self] in self.artistRepository as Any }
+ localTable["fetchArtistListUseCase-any FetchArtistListUseCase"] = { [unowned self] in self.fetchArtistListUseCase as Any }
+ localTable["artistDetailFactory-any ArtistDetailFactory"] = { [unowned self] in self.artistDetailFactory as Any }
+ localTable["fetchArtistDetailUseCase-any FetchArtistDetailUseCase"] = { [unowned self] in self.fetchArtistDetailUseCase as Any }
+ localTable["fetchArtistSongListUseCase-any FetchArtistSongListUseCase"] = { [unowned self] in self.fetchArtistSongListUseCase as Any }
+ localTable["fetchArtistSubscriptionStatusUseCase-any FetchArtistSubscriptionStatusUseCase"] = { [unowned self] in self.fetchArtistSubscriptionStatusUseCase as Any }
+ localTable["subscriptionArtistUseCase-any SubscriptionArtistUseCase"] = { [unowned self] in self.subscriptionArtistUseCase as Any }
+ localTable["findArtistIDUseCase-any FindArtistIDUseCase"] = { [unowned self] in self.findArtistIDUseCase as Any }
+ localTable["artistMusicComponent-ArtistMusicComponent"] = { [unowned self] in self.artistMusicComponent as Any }
+ localTable["artistMusicContentComponent-ArtistMusicContentComponent"] = { [unowned self] in self.artistMusicContentComponent as Any }
+ localTable["remoteUserDataSource-any RemoteUserDataSource"] = { [unowned self] in self.remoteUserDataSource as Any }
+ localTable["userRepository-any UserRepository"] = { [unowned self] in self.userRepository as Any }
+ localTable["setProfileUseCase-any SetProfileUseCase"] = { [unowned self] in self.setProfileUseCase as Any }
+ localTable["setUserNameUseCase-any SetUserNameUseCase"] = { [unowned self] in self.setUserNameUseCase as Any }
+ localTable["fetchPlayListUseCase-any FetchPlaylistUseCase"] = { [unowned self] in self.fetchPlayListUseCase as Any }
+ localTable["fetchFavoriteSongsUseCase-any FetchFavoriteSongsUseCase"] = { [unowned self] in self.fetchFavoriteSongsUseCase as Any }
+ localTable["editFavoriteSongsOrderUseCase-any EditFavoriteSongsOrderUseCase"] = { [unowned self] in self.editFavoriteSongsOrderUseCase as Any }
+ localTable["editPlayListOrderUseCase-any EditPlaylistOrderUseCase"] = { [unowned self] in self.editPlayListOrderUseCase as Any }
+ localTable["deletePlayListUseCase-any DeletePlaylistUseCase"] = { [unowned self] in self.deletePlayListUseCase as Any }
+ localTable["deleteFavoriteListUseCase-any DeleteFavoriteListUseCase"] = { [unowned self] in self.deleteFavoriteListUseCase as Any }
+ localTable["fetchUserInfoUseCase-any FetchUserInfoUseCase"] = { [unowned self] in self.fetchUserInfoUseCase as Any }
+ localTable["withdrawUserInfoUseCase-any WithdrawUserInfoUseCase"] = { [unowned self] in self.withdrawUserInfoUseCase as Any }
+ localTable["fetchFruitListUseCase-any FetchFruitListUseCase"] = { [unowned self] in self.fetchFruitListUseCase as Any }
+ localTable["fetchFruitDrawStatusUseCase-any FetchFruitDrawStatusUseCase"] = { [unowned self] in self.fetchFruitDrawStatusUseCase as Any }
+ localTable["drawFruitUseCase-any DrawFruitUseCase"] = { [unowned self] in self.drawFruitUseCase as Any }
+ localTable["mainContainerComponent-MainContainerComponent"] = { [unowned self] in self.mainContainerComponent as Any }
+ localTable["bottomTabBarComponent-BottomTabBarComponent"] = { [unowned self] in self.bottomTabBarComponent as Any }
+ localTable["mainTabBarComponent-MainTabBarComponent"] = { [unowned self] in self.mainTabBarComponent as Any }
+ localTable["appEntryState-any AppEntryStateHandleable"] = { [unowned self] in self.appEntryState as Any }
+ localTable["permissionComponent-PermissionComponent"] = { [unowned self] in self.permissionComponent as Any }
+ localTable["teamInfoFactory-any TeamInfoFactory"] = { [unowned self] in self.teamInfoFactory as Any }
+ localTable["remoteTeamDataSource-any RemoteTeamDataSource"] = { [unowned self] in self.remoteTeamDataSource as Any }
+ localTable["teamRepository-any TeamRepository"] = { [unowned self] in self.teamRepository as Any }
+ localTable["fetchTeamListUseCase-any FetchTeamListUseCase"] = { [unowned self] in self.fetchTeamListUseCase as Any }
+ localTable["noticePopupComponent-NoticePopupComponent"] = { [unowned self] in self.noticePopupComponent as Any }
+ localTable["noticeFactory-any NoticeFactory"] = { [unowned self] in self.noticeFactory as Any }
+ localTable["noticeDetailFactory-any NoticeDetailFactory"] = { [unowned self] in self.noticeDetailFactory as Any }
+ localTable["remoteNoticeDataSource-any RemoteNoticeDataSource"] = { [unowned self] in self.remoteNoticeDataSource as Any }
+ localTable["noticeRepository-any NoticeRepository"] = { [unowned self] in self.noticeRepository as Any }
+ localTable["fetchNoticeAllUseCase-any FetchNoticeAllUseCase"] = { [unowned self] in self.fetchNoticeAllUseCase as Any }
+ localTable["fetchNoticePopupUseCase-any FetchNoticePopupUseCase"] = { [unowned self] in self.fetchNoticePopupUseCase as Any }
+ localTable["fetchNoticeCategoriesUseCase-any FetchNoticeCategoriesUseCase"] = { [unowned self] in self.fetchNoticeCategoriesUseCase as Any }
+ localTable["fetchNoticeIDListUseCase-any FetchNoticeIDListUseCase"] = { [unowned self] in self.fetchNoticeIDListUseCase as Any }
+ localTable["multiPurposePopupFactory-any MultiPurposePopupFactory"] = { [unowned self] in self.multiPurposePopupFactory as Any }
+ localTable["textPopupFactory-any TextPopupFactory"] = { [unowned self] in self.textPopupFactory as Any }
+ localTable["containSongsFactory-any ContainSongsFactory"] = { [unowned self] in self.containSongsFactory as Any }
+ localTable["privacyFactory-any PrivacyFactory"] = { [unowned self] in self.privacyFactory as Any }
+ localTable["serviceTermsFactory-any ServiceTermFactory"] = { [unowned self] in self.serviceTermsFactory as Any }
+ localTable["storageFactory-any StorageFactory"] = { [unowned self] in self.storageFactory as Any }
+ localTable["listStorageComponent-ListStorageComponent"] = { [unowned self] in self.listStorageComponent as Any }
+ localTable["likeStorageComponent-LikeStorageComponent"] = { [unowned self] in self.likeStorageComponent as Any }
+ localTable["remoteFaqDataSource-any RemoteFaqDataSource"] = { [unowned self] in self.remoteFaqDataSource as Any }
+ localTable["faqRepository-any FaqRepository"] = { [unowned self] in self.faqRepository as Any }
+ localTable["fetchFaqCategoriesUseCase-any FetchFaqCategoriesUseCase"] = { [unowned self] in self.fetchFaqCategoriesUseCase as Any }
+ localTable["fetchFaqUseCase-any FetchFaqUseCase"] = { [unowned self] in self.fetchFaqUseCase as Any }
+ localTable["remoteAppDataSource-any RemoteAppDataSource"] = { [unowned self] in self.remoteAppDataSource as Any }
+ localTable["appRepository-any AppRepository"] = { [unowned self] in self.appRepository as Any }
+ localTable["fetchAppCheckUseCase-any FetchAppCheckUseCase"] = { [unowned self] in self.fetchAppCheckUseCase as Any }
+ localTable["chartFactory-any ChartFactory"] = { [unowned self] in self.chartFactory as Any }
+ localTable["chartContentComponent-ChartContentComponent"] = { [unowned self] in self.chartContentComponent as Any }
+ localTable["remoteChartDataSource-any RemoteChartDataSource"] = { [unowned self] in self.remoteChartDataSource as Any }
+ localTable["chartRepository-any ChartRepository"] = { [unowned self] in self.chartRepository as Any }
+ localTable["fetchChartRankingUseCase-any FetchChartRankingUseCase"] = { [unowned self] in self.fetchChartRankingUseCase as Any }
+ localTable["fetchCurrentVideoUseCase-any FetchCurrentVideoUseCase"] = { [unowned self] in self.fetchCurrentVideoUseCase as Any }
+ }
+}
+@MainActor extension ArtistComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ArtistDependency.fetchArtistListUseCase] = "fetchArtistListUseCase-any FetchArtistListUseCase"
+ keyPathToName[\ArtistDependency.artistDetailFactory] = "artistDetailFactory-any ArtistDetailFactory"
+ }
+}
+@MainActor extension ArtistDetailComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ArtistDetailDependency.artistMusicComponent] = "artistMusicComponent-ArtistMusicComponent"
+ keyPathToName[\ArtistDetailDependency.fetchArtistDetailUseCase] = "fetchArtistDetailUseCase-any FetchArtistDetailUseCase"
+ keyPathToName[\ArtistDetailDependency.fetchArtistSubscriptionStatusUseCase] = "fetchArtistSubscriptionStatusUseCase-any FetchArtistSubscriptionStatusUseCase"
+ keyPathToName[\ArtistDetailDependency.subscriptionArtistUseCase] = "subscriptionArtistUseCase-any SubscriptionArtistUseCase"
+ keyPathToName[\ArtistDetailDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\ArtistDetailDependency.signInFactory] = "signInFactory-any SignInFactory"
+ }
+}
+@MainActor extension ArtistMusicContentComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ArtistMusicContentDependency.fetchArtistSongListUseCase] = "fetchArtistSongListUseCase-any FetchArtistSongListUseCase"
+ keyPathToName[\ArtistMusicContentDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\ArtistMusicContentDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\ArtistMusicContentDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\ArtistMusicContentDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ }
+}
+@MainActor extension ArtistMusicComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ArtistMusicDependency.artistMusicContentComponent] = "artistMusicContentComponent-ArtistMusicContentComponent"
+ }
+}
+@MainActor extension LyricHighlightingComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\LyricHighlightingDependency.fetchLyricsUseCase] = "fetchLyricsUseCase-any FetchLyricsUseCase"
+ keyPathToName[\LyricHighlightingDependency.lyricDecoratingComponent] = "lyricDecoratingComponent-LyricDecoratingComponent"
+ keyPathToName[\LyricHighlightingDependency.lyricHighlightingFactory] = "lyricHighlightingFactory-any LyricHighlightingFactory"
+ }
+}
+@MainActor extension LyricDecoratingComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\LyricDecoratingDependency.fetchLyricDecoratingBackgroundUseCase] = "fetchLyricDecoratingBackgroundUseCase-any FetchLyricDecoratingBackgroundUseCase"
+ keyPathToName[\LyricDecoratingDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ }
+}
+@MainActor extension MainTabBarComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\MainTabBarDependency.fetchNoticePopupUseCase] = "fetchNoticePopupUseCase-any FetchNoticePopupUseCase"
+ keyPathToName[\MainTabBarDependency.fetchNoticeIDListUseCase] = "fetchNoticeIDListUseCase-any FetchNoticeIDListUseCase"
+ keyPathToName[\MainTabBarDependency.updateNotificationTokenUseCase] = "updateNotificationTokenUseCase-any UpdateNotificationTokenUseCase"
+ keyPathToName[\MainTabBarDependency.fetchSongUseCase] = "fetchSongUseCase-any FetchSongUseCase"
+ keyPathToName[\MainTabBarDependency.appEntryState] = "appEntryState-any AppEntryStateHandleable"
+ keyPathToName[\MainTabBarDependency.homeFactory] = "homeFactory-any HomeFactory"
+ keyPathToName[\MainTabBarDependency.searchFactory] = "searchFactory-any SearchFactory"
+ keyPathToName[\MainTabBarDependency.artistFactory] = "artistFactory-any ArtistFactory"
+ keyPathToName[\MainTabBarDependency.storageFactory] = "storageFactory-any StorageFactory"
+ keyPathToName[\MainTabBarDependency.myInfoFactory] = "myInfoFactory-any MyInfoFactory"
+ keyPathToName[\MainTabBarDependency.noticePopupComponent] = "noticePopupComponent-NoticePopupComponent"
+ keyPathToName[\MainTabBarDependency.noticeDetailFactory] = "noticeDetailFactory-any NoticeDetailFactory"
+ keyPathToName[\MainTabBarDependency.playlistDetailFactory] = "playlistDetailFactory-any PlaylistDetailFactory"
+ keyPathToName[\MainTabBarDependency.musicDetailFactory] = "musicDetailFactory-any MusicDetailFactory"
+ keyPathToName[\MainTabBarDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ }
+}
+@MainActor extension BottomTabBarComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension MainContainerComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\MainContainerDependency.bottomTabBarComponent] = "bottomTabBarComponent-BottomTabBarComponent"
+ keyPathToName[\MainContainerDependency.mainTabBarComponent] = "mainTabBarComponent-MainTabBarComponent"
+ keyPathToName[\MainContainerDependency.playlistFactory] = "playlistFactory-any PlaylistFactory"
+ keyPathToName[\MainContainerDependency.playlistPresenterGlobalState] = "playlistPresenterGlobalState-any PlayListPresenterGlobalStateProtocol"
+ }
+}
+@MainActor extension NoticePopupComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension PlaylistCoverOptionPopupComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\PlaylistCoverOptionPopupDependency.fetchPlaylistImagePriceUseCase] = "fetchPlaylistImagePriceUseCase-any FetchPlaylistImagePriceUseCase"
+ }
+}
+@MainActor extension PlaylistDetailComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\PlaylistDetailFactoryDependency.myPlaylistDetailFactory] = "myPlaylistDetailFactory-any MyPlaylistDetailFactory"
+ keyPathToName[\PlaylistDetailFactoryDependency.unknownPlaylistDetailFactory] = "unknownPlaylistDetailFactory-any UnknownPlaylistDetailFactory"
+ keyPathToName[\PlaylistDetailFactoryDependency.wakmusicPlaylistDetailFactory] = "wakmusicPlaylistDetailFactory-any WakmusicPlaylistDetailFactory"
+ keyPathToName[\PlaylistDetailFactoryDependency.requestPlaylistOwnerIDUsecase] = "requestPlaylistOwnerIDUsecase-any RequestPlaylistOwnerIDUsecase"
+ keyPathToName[\PlaylistDetailFactoryDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ }
+}
+@MainActor extension WakmusicPlaylistDetailComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\WakmusicPlaylistDetailDependency.fetchWMPlaylistDetailUseCase] = "fetchWMPlaylistDetailUseCase-any FetchWMPlaylistDetailUseCase"
+ keyPathToName[\WakmusicPlaylistDetailDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\WakmusicPlaylistDetailDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\WakmusicPlaylistDetailDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ keyPathToName[\WakmusicPlaylistDetailDependency.signInFactory] = "signInFactory-any SignInFactory"
+ }
+}
+@MainActor extension MyPlaylistDetailComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\MyPlaylistDetailDependency.fetchPlaylistDetailUseCase] = "fetchPlaylistDetailUseCase-any FetchPlaylistDetailUseCase"
+ keyPathToName[\MyPlaylistDetailDependency.updatePlaylistUseCase] = "updatePlaylistUseCase-any UpdatePlaylistUseCase"
+ keyPathToName[\MyPlaylistDetailDependency.updateTitleAndPrivateUseCase] = "updateTitleAndPrivateUseCase-any UpdateTitleAndPrivateUseCase"
+ keyPathToName[\MyPlaylistDetailDependency.removeSongsUseCase] = "removeSongsUseCase-any RemoveSongsUseCase"
+ keyPathToName[\MyPlaylistDetailDependency.uploadDefaultPlaylistImageUseCase] = "uploadDefaultPlaylistImageUseCase-any UploadDefaultPlaylistImageUseCase"
+ keyPathToName[\MyPlaylistDetailDependency.logoutUseCase] = "logoutUseCase-any LogoutUseCase"
+ keyPathToName[\MyPlaylistDetailDependency.multiPurposePopupFactory] = "multiPurposePopupFactory-any MultiPurposePopupFactory"
+ keyPathToName[\MyPlaylistDetailDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\MyPlaylistDetailDependency.playlistCoverOptionPopupFactory] = "playlistCoverOptionPopupFactory-any PlaylistCoverOptionPopupFactory"
+ keyPathToName[\MyPlaylistDetailDependency.checkPlaylistCoverFactory] = "checkPlaylistCoverFactory-any CheckPlaylistCoverFactory"
+ keyPathToName[\MyPlaylistDetailDependency.defaultPlaylistCoverFactory] = "defaultPlaylistCoverFactory-any DefaultPlaylistCoverFactory"
+ keyPathToName[\MyPlaylistDetailDependency.requestCustomImageURLUseCase] = "requestCustomImageURLUseCase-any RequestCustomImageURLUseCase"
+ keyPathToName[\MyPlaylistDetailDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ keyPathToName[\MyPlaylistDetailDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ }
+}
+@MainActor extension DefaultPlaylistCoverComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\DefaultPlaylistCoverDependency.fetchDefaultPlaylistImageUseCase] = "fetchDefaultPlaylistImageUseCase-any FetchDefaultPlaylistImageUseCase"
+ }
+}
+@MainActor extension PlaylistComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\PlaylistDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\PlaylistDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ keyPathToName[\PlaylistDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\PlaylistDependency.signInFactory] = "signInFactory-any SignInFactory"
+ }
+}
+@MainActor extension UnknownPlaylistDetailComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\UnknownPlaylistDetailDependency.fetchPlaylistDetailUseCase] = "fetchPlaylistDetailUseCase-any FetchPlaylistDetailUseCase"
+ keyPathToName[\UnknownPlaylistDetailDependency.subscribePlaylistUseCase] = "subscribePlaylistUseCase-any SubscribePlaylistUseCase"
+ keyPathToName[\UnknownPlaylistDetailDependency.checkSubscriptionUseCase] = "checkSubscriptionUseCase-any CheckSubscriptionUseCase"
+ keyPathToName[\UnknownPlaylistDetailDependency.logoutUseCase] = "logoutUseCase-any LogoutUseCase"
+ keyPathToName[\UnknownPlaylistDetailDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\UnknownPlaylistDetailDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ keyPathToName[\UnknownPlaylistDetailDependency.signInFactory] = "signInFactory-any SignInFactory"
+ }
+}
+@MainActor extension CheckPlaylistCoverComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\CheckPlaylistCoverDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ }
+}
+@MainActor extension FruitStorageComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\FruitStorageDependency.fetchFruitListUseCase] = "fetchFruitListUseCase-any FetchFruitListUseCase"
+ keyPathToName[\FruitStorageDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ }
+}
+@MainActor extension FruitDrawComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\FruitDrawDependency.fetchFruitDrawStatusUseCase] = "fetchFruitDrawStatusUseCase-any FetchFruitDrawStatusUseCase"
+ keyPathToName[\FruitDrawDependency.drawFruitUseCase] = "drawFruitUseCase-any DrawFruitUseCase"
+ keyPathToName[\FruitDrawDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ }
+}
+@MainActor extension CreditSongListTabItemComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\CreditSongListTabItemDependency.fetchCreditSongListUseCase] = "fetchCreditSongListUseCase-any FetchCreditSongListUseCase"
+ keyPathToName[\CreditSongListTabItemDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\CreditSongListTabItemDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\CreditSongListTabItemDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\CreditSongListTabItemDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ }
+}
+@MainActor extension CreditSongListTabComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\CreditSongListTabDependency.creditSongListTabItemFactory] = "creditSongListTabItemFactory-any CreditSongListTabItemFactory"
+ }
+}
+@MainActor extension CreditSongListComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\CreditSongListDependency.creditSongListTabFactory] = "creditSongListTabFactory-any CreditSongListTabFactory"
+ keyPathToName[\CreditSongListDependency.fetchCreditProfileUseCase] = "fetchCreditProfileUseCase-any FetchCreditProfileUseCase"
+ }
+}
+@MainActor extension ChartComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ChartDependency.chartContentComponent] = "chartContentComponent-ChartContentComponent"
+ }
+}
+@MainActor extension ChartContentComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ChartContentDependency.fetchChartRankingUseCase] = "fetchChartRankingUseCase-any FetchChartRankingUseCase"
+ keyPathToName[\ChartContentDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\ChartContentDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\ChartContentDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\ChartContentDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ }
+}
+@MainActor extension TeamInfoComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\TeamInfoDependency.fetchTeamListUseCase] = "fetchTeamListUseCase-any FetchTeamListUseCase"
+ }
+}
+@MainActor extension StorageComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\StorageDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\StorageDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\StorageDependency.multiPurposePopupFactory] = "multiPurposePopupFactory-any MultiPurposePopupFactory"
+ keyPathToName[\StorageDependency.listStorageComponent] = "listStorageComponent-ListStorageComponent"
+ keyPathToName[\StorageDependency.likeStorageComponent] = "likeStorageComponent-LikeStorageComponent"
+ }
+}
+@MainActor extension ListStorageComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ListStorageDependency.multiPurposePopupFactory] = "multiPurposePopupFactory-any MultiPurposePopupFactory"
+ keyPathToName[\ListStorageDependency.playlistDetailFactory] = "playlistDetailFactory-any PlaylistDetailFactory"
+ keyPathToName[\ListStorageDependency.createPlaylistUseCase] = "createPlaylistUseCase-any CreatePlaylistUseCase"
+ keyPathToName[\ListStorageDependency.editPlayListOrderUseCase] = "editPlayListOrderUseCase-any EditPlaylistOrderUseCase"
+ keyPathToName[\ListStorageDependency.fetchPlayListUseCase] = "fetchPlayListUseCase-any FetchPlaylistUseCase"
+ keyPathToName[\ListStorageDependency.deletePlayListUseCase] = "deletePlayListUseCase-any DeletePlaylistUseCase"
+ keyPathToName[\ListStorageDependency.fetchPlaylistSongsUseCase] = "fetchPlaylistSongsUseCase-any FetchPlaylistSongsUseCase"
+ keyPathToName[\ListStorageDependency.fetchPlaylistCreationPriceUseCase] = "fetchPlaylistCreationPriceUseCase-any FetchPlaylistCreationPriceUseCase"
+ keyPathToName[\ListStorageDependency.logoutUseCase] = "logoutUseCase-any LogoutUseCase"
+ keyPathToName[\ListStorageDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\ListStorageDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\ListStorageDependency.fruitDrawFactory] = "fruitDrawFactory-any FruitDrawFactory"
+ }
+}
+@MainActor extension LikeStorageComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\LikeStorageDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\LikeStorageDependency.fetchFavoriteSongsUseCase] = "fetchFavoriteSongsUseCase-any FetchFavoriteSongsUseCase"
+ keyPathToName[\LikeStorageDependency.editFavoriteSongsOrderUseCase] = "editFavoriteSongsOrderUseCase-any EditFavoriteSongsOrderUseCase"
+ keyPathToName[\LikeStorageDependency.deleteFavoriteListUseCase] = "deleteFavoriteListUseCase-any DeleteFavoriteListUseCase"
+ keyPathToName[\LikeStorageDependency.logoutUseCase] = "logoutUseCase-any LogoutUseCase"
+ keyPathToName[\LikeStorageDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\LikeStorageDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\LikeStorageDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ }
+}
+@MainActor extension RootComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\RootDependency.mainContainerComponent] = "mainContainerComponent-MainContainerComponent"
+ keyPathToName[\RootDependency.permissionComponent] = "permissionComponent-PermissionComponent"
+ keyPathToName[\RootDependency.fetchUserInfoUseCase] = "fetchUserInfoUseCase-any FetchUserInfoUseCase"
+ keyPathToName[\RootDependency.fetchAppCheckUseCase] = "fetchAppCheckUseCase-any FetchAppCheckUseCase"
+ keyPathToName[\RootDependency.logoutUseCase] = "logoutUseCase-any LogoutUseCase"
+ keyPathToName[\RootDependency.checkIsExistAccessTokenUseCase] = "checkIsExistAccessTokenUseCase-any CheckIsExistAccessTokenUseCase"
+ keyPathToName[\RootDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ }
+}
+@MainActor extension PermissionComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension SignInComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\SignInDependency.fetchTokenUseCase] = "fetchTokenUseCase-any FetchTokenUseCase"
+ keyPathToName[\SignInDependency.fetchUserInfoUseCase] = "fetchUserInfoUseCase-any FetchUserInfoUseCase"
+ }
+}
+@MainActor extension NewSongsComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\NewSongsDependency.newSongsContentComponent] = "newSongsContentComponent-NewSongsContentComponent"
+ }
+}
+@MainActor extension HomeComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\HomeDependency.fetchChartRankingUseCase] = "fetchChartRankingUseCase-any FetchChartRankingUseCase"
+ keyPathToName[\HomeDependency.fetchNewSongsUseCase] = "fetchNewSongsUseCase-any FetchNewSongsUseCase"
+ keyPathToName[\HomeDependency.fetchRecommendPlaylistUseCase] = "fetchRecommendPlaylistUseCase-any FetchRecommendPlaylistUseCase"
+ keyPathToName[\HomeDependency.playlistDetailFactory] = "playlistDetailFactory-any PlaylistDetailFactory"
+ keyPathToName[\HomeDependency.chartFactory] = "chartFactory-any ChartFactory"
+ keyPathToName[\HomeDependency.newSongsComponent] = "newSongsComponent-NewSongsComponent"
+ keyPathToName[\HomeDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ }
+}
+@MainActor extension NewSongsContentComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\NewSongsContentDependency.fetchNewSongsUseCase] = "fetchNewSongsUseCase-any FetchNewSongsUseCase"
+ keyPathToName[\NewSongsContentDependency.fetchNewSongsPlaylistUseCase] = "fetchNewSongsPlaylistUseCase-any FetchNewSongsPlaylistUseCase"
+ keyPathToName[\NewSongsContentDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\NewSongsContentDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\NewSongsContentDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\NewSongsContentDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ }
+}
+@MainActor extension WakmusicRecommendComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\WakmusicRecommendDependency.fetchRecommendPlaylistUseCase] = "fetchRecommendPlaylistUseCase-any FetchRecommendPlaylistUseCase"
+ keyPathToName[\WakmusicRecommendDependency.wakmusicPlaylistDetailFactory] = "wakmusicPlaylistDetailFactory-any WakmusicPlaylistDetailFactory"
+ }
+}
+@MainActor extension BeforeSearchComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\BeforeSearchDependency.fetchRecommendPlaylistUseCase] = "fetchRecommendPlaylistUseCase-any FetchRecommendPlaylistUseCase"
+ keyPathToName[\BeforeSearchDependency.fetchCurrentVideoUseCase] = "fetchCurrentVideoUseCase-any FetchCurrentVideoUseCase"
+ keyPathToName[\BeforeSearchDependency.wakmusicRecommendComponent] = "wakmusicRecommendComponent-WakmusicRecommendComponent"
+ keyPathToName[\BeforeSearchDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\BeforeSearchDependency.playlistDetailFactory] = "playlistDetailFactory-any PlaylistDetailFactory"
+ }
+}
+@MainActor extension SearchComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\SearchDependency.beforeSearchComponent] = "beforeSearchComponent-BeforeSearchComponent"
+ keyPathToName[\SearchDependency.afterSearchComponent] = "afterSearchComponent-AfterSearchComponent"
+ keyPathToName[\SearchDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\SearchDependency.searchGlobalScrollState] = "searchGlobalScrollState-any SearchGlobalScrollProtocol"
+ }
+}
+@MainActor extension AfterSearchComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\AfterSearchDependency.songSearchResultFactory] = "songSearchResultFactory-any SongSearchResultFactory"
+ keyPathToName[\AfterSearchDependency.listSearchResultFactory] = "listSearchResultFactory-any ListSearchResultFactory"
+ keyPathToName[\AfterSearchDependency.searchGlobalScrollState] = "searchGlobalScrollState-any SearchGlobalScrollProtocol"
+ }
+}
+@MainActor extension ListSearchResultComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ListSearchResultDependency.fetchSearchPlaylistsUseCase] = "fetchSearchPlaylistsUseCase-any FetchSearchPlaylistsUseCase"
+ keyPathToName[\ListSearchResultDependency.searchSortOptionComponent] = "searchSortOptionComponent-SearchSortOptionComponent"
+ keyPathToName[\ListSearchResultDependency.playlistDetailFactory] = "playlistDetailFactory-any PlaylistDetailFactory"
+ keyPathToName[\ListSearchResultDependency.searchGlobalScrollState] = "searchGlobalScrollState-any SearchGlobalScrollProtocol"
+ }
+}
+@MainActor extension SongSearchResultComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\SongSearchResultDependency.fetchSearchSongsUseCase] = "fetchSearchSongsUseCase-any FetchSearchSongsUseCase"
+ keyPathToName[\SongSearchResultDependency.searchSortOptionComponent] = "searchSortOptionComponent-SearchSortOptionComponent"
+ keyPathToName[\SongSearchResultDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\SongSearchResultDependency.searchGlobalScrollState] = "searchGlobalScrollState-any SearchGlobalScrollProtocol"
+ keyPathToName[\SongSearchResultDependency.songDetailPresenter] = "songDetailPresenter-any SongDetailPresentable"
+ keyPathToName[\SongSearchResultDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\SongSearchResultDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ }
+}
+@MainActor extension SearchSortOptionComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension ContainSongsComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ContainSongsDependency.multiPurposePopupFactory] = "multiPurposePopupFactory-any MultiPurposePopupFactory"
+ keyPathToName[\ContainSongsDependency.fetchPlayListUseCase] = "fetchPlayListUseCase-any FetchPlaylistUseCase"
+ keyPathToName[\ContainSongsDependency.addSongIntoPlaylistUseCase] = "addSongIntoPlaylistUseCase-any AddSongIntoPlaylistUseCase"
+ keyPathToName[\ContainSongsDependency.createPlaylistUseCase] = "createPlaylistUseCase-any CreatePlaylistUseCase"
+ keyPathToName[\ContainSongsDependency.fetchPlaylistCreationPriceUseCase] = "fetchPlaylistCreationPriceUseCase-any FetchPlaylistCreationPriceUseCase"
+ keyPathToName[\ContainSongsDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\ContainSongsDependency.logoutUseCase] = "logoutUseCase-any LogoutUseCase"
+ }
+}
+@MainActor extension MultiPurposePopupComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension TextPopupComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension ServiceTermsComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension PrivacyComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension ServiceInfoComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ServiceInfoDependency.openSourceLicenseFactory] = "openSourceLicenseFactory-any OpenSourceLicenseFactory"
+ keyPathToName[\ServiceInfoDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ }
+}
+@MainActor extension PlayTypeTogglePopupComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension FaqComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\FaqDependency.faqContentFactory] = "faqContentFactory-any FaqContentFactory"
+ keyPathToName[\FaqDependency.fetchFaqCategoriesUseCase] = "fetchFaqCategoriesUseCase-any FetchFaqCategoriesUseCase"
+ keyPathToName[\FaqDependency.fetchFaqUseCase] = "fetchFaqUseCase-any FetchFaqUseCase"
+ }
+}
+@MainActor extension QuestionComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\QuestionDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ }
+}
+@MainActor extension MyInfoComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\MyInfoDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\MyInfoDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\MyInfoDependency.multiPurposePopupFactory] = "multiPurposePopupFactory-any MultiPurposePopupFactory"
+ keyPathToName[\MyInfoDependency.faqFactory] = "faqFactory-any FaqFactory"
+ keyPathToName[\MyInfoDependency.noticeFactory] = "noticeFactory-any NoticeFactory"
+ keyPathToName[\MyInfoDependency.questionFactory] = "questionFactory-any QuestionFactory"
+ keyPathToName[\MyInfoDependency.teamInfoFactory] = "teamInfoFactory-any TeamInfoFactory"
+ keyPathToName[\MyInfoDependency.settingFactory] = "settingFactory-any SettingFactory"
+ keyPathToName[\MyInfoDependency.profilePopupFactory] = "profilePopupFactory-any ProfilePopupFactory"
+ keyPathToName[\MyInfoDependency.fruitDrawFactory] = "fruitDrawFactory-any FruitDrawFactory"
+ keyPathToName[\MyInfoDependency.fruitStorageFactory] = "fruitStorageFactory-any FruitStorageFactory"
+ keyPathToName[\MyInfoDependency.fetchNoticeIDListUseCase] = "fetchNoticeIDListUseCase-any FetchNoticeIDListUseCase"
+ keyPathToName[\MyInfoDependency.setUserNameUseCase] = "setUserNameUseCase-any SetUserNameUseCase"
+ keyPathToName[\MyInfoDependency.fetchUserInfoUseCase] = "fetchUserInfoUseCase-any FetchUserInfoUseCase"
+ }
+}
+@MainActor extension SettingComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\SettingDependency.withdrawUserInfoUseCase] = "withdrawUserInfoUseCase-any WithdrawUserInfoUseCase"
+ keyPathToName[\SettingDependency.logoutUseCase] = "logoutUseCase-any LogoutUseCase"
+ keyPathToName[\SettingDependency.updateNotificationTokenUseCase] = "updateNotificationTokenUseCase-any UpdateNotificationTokenUseCase"
+ keyPathToName[\SettingDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\SettingDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\SettingDependency.serviceTermsFactory] = "serviceTermsFactory-any ServiceTermFactory"
+ keyPathToName[\SettingDependency.privacyFactory] = "privacyFactory-any PrivacyFactory"
+ keyPathToName[\SettingDependency.openSourceLicenseFactory] = "openSourceLicenseFactory-any OpenSourceLicenseFactory"
+ keyPathToName[\SettingDependency.playTypeTogglePopupFactory] = "playTypeTogglePopupFactory-any PlayTypeTogglePopupFactory"
+ }
+}
+@MainActor extension NoticeDetailComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension ProfilePopupComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\ProfilePopupDependency.fetchProfileListUseCase] = "fetchProfileListUseCase-any FetchProfileListUseCase"
+ keyPathToName[\ProfilePopupDependency.setProfileUseCase] = "setProfileUseCase-any SetProfileUseCase"
+ }
+}
+@MainActor extension OpenSourceLicenseComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension NoticeComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\NoticeDependency.fetchNoticeAllUseCase] = "fetchNoticeAllUseCase-any FetchNoticeAllUseCase"
+ keyPathToName[\NoticeDependency.noticeDetailFactory] = "noticeDetailFactory-any NoticeDetailFactory"
+ }
+}
+@MainActor extension FaqContentComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension SongCreditComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\SongCreditDependency.fetchSongCreditsUseCase] = "fetchSongCreditsUseCase-any FetchSongCreditsUseCase"
+ keyPathToName[\SongCreditDependency.creditSongListFactory] = "creditSongListFactory-any CreditSongListFactory"
+ keyPathToName[\SongCreditDependency.artistDetailFactory] = "artistDetailFactory-any ArtistDetailFactory"
+ }
+}
+@MainActor extension KaraokeComponent: Registration {
+ public func registerItems() {
+
+ }
+}
+@MainActor extension MusicDetailComponent: Registration {
+ public func registerItems() {
+ keyPathToName[\MusicDetailDependency.fetchSongUseCase] = "fetchSongUseCase-any FetchSongUseCase"
+ keyPathToName[\MusicDetailDependency.lyricHighlightingFactory] = "lyricHighlightingFactory-any LyricHighlightingFactory"
+ keyPathToName[\MusicDetailDependency.songCreditFactory] = "songCreditFactory-any SongCreditFactory"
+ keyPathToName[\MusicDetailDependency.signInFactory] = "signInFactory-any SignInFactory"
+ keyPathToName[\MusicDetailDependency.containSongsFactory] = "containSongsFactory-any ContainSongsFactory"
+ keyPathToName[\MusicDetailDependency.karaokeFactory] = "karaokeFactory-any KaraokeFactory"
+ keyPathToName[\MusicDetailDependency.textPopupFactory] = "textPopupFactory-any TextPopupFactory"
+ keyPathToName[\MusicDetailDependency.artistDetailFactory] = "artistDetailFactory-any ArtistDetailFactory"
+ keyPathToName[\MusicDetailDependency.playlistPresenterGlobalState] = "playlistPresenterGlobalState-any PlayListPresenterGlobalStateProtocol"
+ keyPathToName[\MusicDetailDependency.addLikeSongUseCase] = "addLikeSongUseCase-any AddLikeSongUseCase"
+ keyPathToName[\MusicDetailDependency.cancelLikeSongUseCase] = "cancelLikeSongUseCase-any CancelLikeSongUseCase"
+ keyPathToName[\MusicDetailDependency.findArtistIDUseCase] = "findArtistIDUseCase-any FindArtistIDUseCase"
+ }
+}
+
+
+#endif
+
+@MainActor private func factoryEmptyDependencyProvider(_ component: NeedleFoundation.Scope) -> AnyObject {
+ return EmptyDependencyProvider(component: component)
+}
+
+// MARK: - Registration
+@MainActor
+private func registerProviderFactory(_ componentPath: String, _ factory: @escaping (NeedleFoundation.Scope) -> AnyObject) {
+ __DependencyProviderRegistry.instance.registerDependencyProviderFactory(for: componentPath, factory)
+}
+
+#if !NEEDLE_DYNAMIC
+
+@MainActor
+@inline(never) private func register1() {
+ registerProviderFactory("^->AppComponent", factoryEmptyDependencyProvider)
+ registerProviderFactory("^->AppComponent->ArtistComponent", factorye0c5444f5894148bdd93f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->ArtistDetailComponent", factory35314797fadaf164ece6f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->ArtistMusicContentComponent", factory8b6ffa46033e2529b5daf47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->ArtistMusicComponent", factory382e7f8466df35a3f1d9f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->LyricHighlightingComponent", factory57ee59e468bef412b173f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->LyricDecoratingComponent", factory5d05db9eb4337d682097f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->MainTabBarComponent", factorye547a52b3fce5887c8c7f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->BottomTabBarComponent", factoryd34fa9e493604a6295bde3b0c44298fc1c149afb)
+ registerProviderFactory("^->AppComponent->MainContainerComponent", factory8e19f48d5d573d3ea539f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->NoticePopupComponent", factorycd081aacb61d6a707ca7e3b0c44298fc1c149afb)
+ registerProviderFactory("^->AppComponent->PlaylistCoverOptionPopupComponent", factory487946b77daee32980aff47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->PlaylistDetailComponent", factory6595408565b754d9f0f7f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->WakmusicPlaylistDetailComponent", factorye3e053cabf65749566c8f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->MyPlaylistDetailComponent", factoryc6efd92ea498eaae7ff8f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->DefaultPlaylistCoverComponent", factory89371387a9e4c131e13df47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->PlaylistComponent", factory3a0a6eb1061d8d5a2deff47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->UnknownPlaylistDetailComponent", factorya6d30d5b4471815dceb2f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->CheckPlaylistCoverComponent", factory025ce9f6d91409a9f719f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->FruitStorageComponent", factory070e42b0224381c8cdf4f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->FruitDrawComponent", factoryc603eb682d7a111dc261f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->CreditSongListTabItemComponent", factory95828465b02bfed94ec5f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->CreditSongListTabComponent", factory85beabbf7f1f193dec41f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->CreditSongListComponent", factorye0caf4db37d0954ab34ef47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->ChartComponent", factoryeac6a4df54bbd391d31bf47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->ChartContentComponent", factoryc9a137630ce76907f36ff47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->TeamInfoComponent", factorybe60e92b5190e00abf41f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->StorageComponent", factory2415399d25299b97b98bf47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->ListStorageComponent", factory75c66cb7534f04d45951f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->LikeStorageComponent", factory9f7222d7c56236b2e993f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->RootComponent", factory264bfc4d4cb6b0629b40f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->PermissionComponent", factoryc1d4d80afbccf86bf1c0e3b0c44298fc1c149afb)
+ registerProviderFactory("^->AppComponent->SignInComponent", factoryda2925fd76da866a652af47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->NewSongsComponent", factory379179b05dd24ff979edf47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->HomeComponent", factory67229cdf0f755562b2b1f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->NewSongsContentComponent", factorye130e1fbfcbc622a4c38f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->WakmusicRecommendComponent", factoryaf1c3535530356714983f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->BeforeSearchComponent", factory9bb852337d5550979293f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->SearchComponent", factorye3d049458b2ccbbcb3b6f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->AfterSearchComponent", factoryeb2da679e35e2c4fb9a5f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->ListSearchResultComponent", factory2c8e2a50d1fcf9efc9f8f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->SongSearchResultComponent", factory182af2382ca6172f89c1f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->SearchSortOptionComponent", factoryEmptyDependencyProvider)
+ registerProviderFactory("^->AppComponent->ContainSongsComponent", factory4d4f4455414271fee232f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->MultiPurposePopupComponent", factoryEmptyDependencyProvider)
+ registerProviderFactory("^->AppComponent->TextPopupComponent", factoryEmptyDependencyProvider)
+ registerProviderFactory("^->AppComponent->ServiceTermsComponent", factory8014909e2d8dba4e4f20e3b0c44298fc1c149afb)
+ registerProviderFactory("^->AppComponent->PrivacyComponent", factorye7f5d59533cfdd1614b0e3b0c44298fc1c149afb)
+ registerProviderFactory("^->AppComponent->ServiceInfoComponent", factory3afd170b9974b0dbd863f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->PlayTypeTogglePopupComponent", factoryEmptyDependencyProvider)
+}
+
+@MainActor
+@inline(never) private func register2() {
+ registerProviderFactory("^->AppComponent->FaqComponent", factory4e13cc6545633ffc2ed5f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->QuestionComponent", factoryedad1813a36115eec11ef47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->MyInfoComponent", factoryec2cede3edc2a626b35df47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->SettingComponent", factoryee0bbc0b920a7007e1a9f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->NoticeDetailComponent", factory3db143c2f80d621d5a7fe3b0c44298fc1c149afb)
+ registerProviderFactory("^->AppComponent->ProfilePopupComponent", factory3a1ad3396729bed7200ef47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->OpenSourceLicenseComponent", factoryd505894818021731340ae3b0c44298fc1c149afb)
+ registerProviderFactory("^->AppComponent->NoticeComponent", factoryaf8e5665e5b9217918f5f47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->FaqContentComponent", factoryEmptyDependencyProvider)
+ registerProviderFactory("^->AppComponent->SongCreditComponent", factoryd48a3e0e81529a27a02bf47b58f8f304c97af4d5)
+ registerProviderFactory("^->AppComponent->KaraokeComponent", factoryEmptyDependencyProvider)
+ registerProviderFactory("^->AppComponent->MusicDetailComponent", factory84f307443e9a78802606f47b58f8f304c97af4d5)
+}
+#endif
+
+@MainActor
+public func registerProviderFactories() {
+#if !NEEDLE_DYNAMIC
+ register1()
+ register2()
+#endif
+}
diff --git a/Projects/App/Sources/Application/SceneDelegate.swift b/Projects/App/Sources/Application/SceneDelegate.swift
index 42cc4a2b5..6722e8805 100644
--- a/Projects/App/Sources/Application/SceneDelegate.swift
+++ b/Projects/App/Sources/Application/SceneDelegate.swift
@@ -19,7 +19,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
self.window = UIWindow(windowScene: scene)
registerProviderFactories()
self.root = AppComponent()
- self.window?.rootViewController = root?.makeRootView().wrapNavigationController
+ self.window?.rootViewController = root?.rootComponent.makeView().wrapNavigationController
self.window?.makeKeyAndVisible()
// Handling App Entry:: Not Running State
diff --git a/Projects/App/Support/Info.plist b/Projects/App/Support/Info.plist
index be1febdff..175f4b095 100644
--- a/Projects/App/Support/Info.plist
+++ b/Projects/App/Support/Info.plist
@@ -55,8 +55,8 @@
LSApplicationQueriesSchemes
- naversearchapp
- naversearchthirdlogin
+ naversearchapp
+ naversearchthirdlogin
youtube
youtubemusic
diff --git a/Projects/Domains/AppDomain/Interface/DataSource/RemoteAppDataSource.swift b/Projects/Domains/AppDomain/Interface/DataSource/RemoteAppDataSource.swift
index 50d3cfcb7..007fba91f 100644
--- a/Projects/Domains/AppDomain/Interface/DataSource/RemoteAppDataSource.swift
+++ b/Projects/Domains/AppDomain/Interface/DataSource/RemoteAppDataSource.swift
@@ -9,6 +9,6 @@
import Foundation
import RxSwift
-public protocol RemoteAppDataSource {
+public protocol RemoteAppDataSource: Sendable {
func fetchAppCheck() -> Single
}
diff --git a/Projects/Domains/AppDomain/Interface/Repository/AppRepository.swift b/Projects/Domains/AppDomain/Interface/Repository/AppRepository.swift
index c7519217f..37a5e3cac 100644
--- a/Projects/Domains/AppDomain/Interface/Repository/AppRepository.swift
+++ b/Projects/Domains/AppDomain/Interface/Repository/AppRepository.swift
@@ -9,6 +9,6 @@
import Foundation
import RxSwift
-public protocol AppRepository {
+public protocol AppRepository: Sendable {
func fetchAppCheck() -> Single
}
diff --git a/Projects/Domains/AppDomain/Interface/UseCase/FetchAppCheckUseCase.swift b/Projects/Domains/AppDomain/Interface/UseCase/FetchAppCheckUseCase.swift
index 5c3bff09f..fdc9d0d2c 100644
--- a/Projects/Domains/AppDomain/Interface/UseCase/FetchAppCheckUseCase.swift
+++ b/Projects/Domains/AppDomain/Interface/UseCase/FetchAppCheckUseCase.swift
@@ -9,6 +9,6 @@
import Foundation
import RxSwift
-public protocol FetchAppCheckUseCase {
+public protocol FetchAppCheckUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/ArtistDomain/Interface/DataSource/RemoteArtistDataSource.swift b/Projects/Domains/ArtistDomain/Interface/DataSource/RemoteArtistDataSource.swift
index b1bb8fc5a..46e3d9837 100644
--- a/Projects/Domains/ArtistDomain/Interface/DataSource/RemoteArtistDataSource.swift
+++ b/Projects/Domains/ArtistDomain/Interface/DataSource/RemoteArtistDataSource.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol RemoteArtistDataSource {
+public protocol RemoteArtistDataSource: Sendable {
func fetchArtistList() -> Single<[ArtistEntity]>
func fetchArtistDetail(id: String) -> Single
func fetchArtistSongList(id: String, sort: ArtistSongSortType, page: Int) -> Single<[ArtistSongListEntity]>
diff --git a/Projects/Domains/ArtistDomain/Interface/Repository/ArtistRepository.swift b/Projects/Domains/ArtistDomain/Interface/Repository/ArtistRepository.swift
index d3aca2a5c..2d6fa8130 100644
--- a/Projects/Domains/ArtistDomain/Interface/Repository/ArtistRepository.swift
+++ b/Projects/Domains/ArtistDomain/Interface/Repository/ArtistRepository.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol ArtistRepository {
+public protocol ArtistRepository: Sendable {
func fetchArtistList() -> Single<[ArtistEntity]>
func fetchArtistDetail(id: String) -> Single
func fetchArtistSongList(id: String, sort: ArtistSongSortType, page: Int) -> Single<[ArtistSongListEntity]>
diff --git a/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistDetailUseCase.swift b/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistDetailUseCase.swift
index f953bebd1..61501401b 100644
--- a/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistDetailUseCase.swift
+++ b/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistDetailUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchArtistDetailUseCase {
+public protocol FetchArtistDetailUseCase: Sendable {
func execute(id: String) -> Single
}
diff --git a/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistListUseCase.swift b/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistListUseCase.swift
index 33071ee5b..59fbaf891 100644
--- a/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistListUseCase.swift
+++ b/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistListUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchArtistListUseCase {
+public protocol FetchArtistListUseCase: Sendable {
func execute() -> Single<[ArtistEntity]>
}
diff --git a/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistSongListUseCase.swift b/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistSongListUseCase.swift
index 8ac70f402..11cdc4418 100644
--- a/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistSongListUseCase.swift
+++ b/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistSongListUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchArtistSongListUseCase {
+public protocol FetchArtistSongListUseCase: Sendable {
func execute(id: String, sort: ArtistSongSortType, page: Int) -> Single<[ArtistSongListEntity]>
}
diff --git a/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistSubscriptionStatusUseCase.swift b/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistSubscriptionStatusUseCase.swift
index 27216630f..2b3b5cbe2 100644
--- a/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistSubscriptionStatusUseCase.swift
+++ b/Projects/Domains/ArtistDomain/Interface/UseCase/FetchArtistSubscriptionStatusUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchArtistSubscriptionStatusUseCase {
+public protocol FetchArtistSubscriptionStatusUseCase: Sendable {
func execute(id: String) -> Single
}
diff --git a/Projects/Domains/ArtistDomain/Interface/UseCase/FindArtistIDUseCase.swift b/Projects/Domains/ArtistDomain/Interface/UseCase/FindArtistIDUseCase.swift
index b2ce2a44e..7b1e01cb8 100644
--- a/Projects/Domains/ArtistDomain/Interface/UseCase/FindArtistIDUseCase.swift
+++ b/Projects/Domains/ArtistDomain/Interface/UseCase/FindArtistIDUseCase.swift
@@ -1,5 +1,5 @@
import RxSwift
-public protocol FindArtistIDUseCase {
+public protocol FindArtistIDUseCase: Sendable {
func execute(name: String) -> Single
}
diff --git a/Projects/Domains/ArtistDomain/Interface/UseCase/SubscriptionArtistUseCase.swift b/Projects/Domains/ArtistDomain/Interface/UseCase/SubscriptionArtistUseCase.swift
index e8bbab6a8..1157ca0b0 100644
--- a/Projects/Domains/ArtistDomain/Interface/UseCase/SubscriptionArtistUseCase.swift
+++ b/Projects/Domains/ArtistDomain/Interface/UseCase/SubscriptionArtistUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol SubscriptionArtistUseCase {
+public protocol SubscriptionArtistUseCase: Sendable {
func execute(id: String, on: Bool) -> Completable
}
diff --git a/Projects/Domains/ArtistDomain/Testing/UseCase/FetchArtistListUseCaseSpy.swift b/Projects/Domains/ArtistDomain/Testing/UseCase/FetchArtistListUseCaseSpy.swift
index 56f15cd9c..acfcb1768 100644
--- a/Projects/Domains/ArtistDomain/Testing/UseCase/FetchArtistListUseCaseSpy.swift
+++ b/Projects/Domains/ArtistDomain/Testing/UseCase/FetchArtistListUseCaseSpy.swift
@@ -2,7 +2,7 @@ import ArtistDomainInterface
import Foundation
import RxSwift
-public final class FetchArtistListUseCaseSpy: FetchArtistListUseCase {
+public final class FetchArtistListUseCaseSpy: FetchArtistListUseCase, @unchecked Sendable {
public private(set) var callCount = 0
public var handler: (() -> Single<[ArtistEntity]>) = { .never() }
public func execute() -> Single<[ArtistEntity]> {
diff --git a/Projects/Domains/ArtistDomain/Testing/UseCase/FindArtistIDUseCaseSpy.swift b/Projects/Domains/ArtistDomain/Testing/UseCase/FindArtistIDUseCaseSpy.swift
index 7a37e5016..d0ca0f12a 100644
--- a/Projects/Domains/ArtistDomain/Testing/UseCase/FindArtistIDUseCaseSpy.swift
+++ b/Projects/Domains/ArtistDomain/Testing/UseCase/FindArtistIDUseCaseSpy.swift
@@ -1,7 +1,7 @@
import ArtistDomainInterface
import RxSwift
-public final class FindArtistIDUseCaseSpy: FindArtistIDUseCase {
+public final class FindArtistIDUseCaseSpy: FindArtistIDUseCase, @unchecked Sendable {
public private(set) var callCount = 0
public var handler: ((String) -> Single) = { _ in .never() }
public func execute(name: String) -> Single {
diff --git a/Projects/Domains/AuthDomain/Interface/DataSource/LocalAuthDataSource.swift b/Projects/Domains/AuthDomain/Interface/DataSource/LocalAuthDataSource.swift
index 524736e50..b4f4fe7ce 100644
--- a/Projects/Domains/AuthDomain/Interface/DataSource/LocalAuthDataSource.swift
+++ b/Projects/Domains/AuthDomain/Interface/DataSource/LocalAuthDataSource.swift
@@ -1,6 +1,6 @@
import RxSwift
-public protocol LocalAuthDataSource {
+public protocol LocalAuthDataSource: Sendable {
func logout()
func checkIsExistAccessToken() -> Bool
}
diff --git a/Projects/Domains/AuthDomain/Interface/DataSource/RemoteAuthDataSource.swift b/Projects/Domains/AuthDomain/Interface/DataSource/RemoteAuthDataSource.swift
index 966dbf858..422f89856 100644
--- a/Projects/Domains/AuthDomain/Interface/DataSource/RemoteAuthDataSource.swift
+++ b/Projects/Domains/AuthDomain/Interface/DataSource/RemoteAuthDataSource.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol RemoteAuthDataSource {
+public protocol RemoteAuthDataSource: Sendable {
func fetchToken(providerType: ProviderType, token: String) -> Single
func reGenerateAccessToken() -> Single
func logout() -> Completable
diff --git a/Projects/Domains/AuthDomain/Interface/Repository/AuthRepository.swift b/Projects/Domains/AuthDomain/Interface/Repository/AuthRepository.swift
index ffa21aa9b..2f64eea3b 100644
--- a/Projects/Domains/AuthDomain/Interface/Repository/AuthRepository.swift
+++ b/Projects/Domains/AuthDomain/Interface/Repository/AuthRepository.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol AuthRepository {
+public protocol AuthRepository: Sendable {
func fetchToken(providerType: ProviderType, token: String) -> Single
func reGenerateAccessToken() -> Single
func logout(localOnly: Bool) -> Completable
diff --git a/Projects/Domains/AuthDomain/Interface/UseCase/CheckIsExistAccessTokenUseCase.swift b/Projects/Domains/AuthDomain/Interface/UseCase/CheckIsExistAccessTokenUseCase.swift
index 434275268..51a55c2ac 100644
--- a/Projects/Domains/AuthDomain/Interface/UseCase/CheckIsExistAccessTokenUseCase.swift
+++ b/Projects/Domains/AuthDomain/Interface/UseCase/CheckIsExistAccessTokenUseCase.swift
@@ -1,5 +1,5 @@
import RxSwift
-public protocol CheckIsExistAccessTokenUseCase {
+public protocol CheckIsExistAccessTokenUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/AuthDomain/Interface/UseCase/FetchTokenUseCase.swift b/Projects/Domains/AuthDomain/Interface/UseCase/FetchTokenUseCase.swift
index 4a8b6cfa7..56ab76b9d 100644
--- a/Projects/Domains/AuthDomain/Interface/UseCase/FetchTokenUseCase.swift
+++ b/Projects/Domains/AuthDomain/Interface/UseCase/FetchTokenUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchTokenUseCase {
+public protocol FetchTokenUseCase: Sendable {
func execute(providerType: ProviderType, token: String) -> Single
}
diff --git a/Projects/Domains/AuthDomain/Interface/UseCase/LogoutUseCase.swift b/Projects/Domains/AuthDomain/Interface/UseCase/LogoutUseCase.swift
index 8c81f1735..ad7a78b04 100644
--- a/Projects/Domains/AuthDomain/Interface/UseCase/LogoutUseCase.swift
+++ b/Projects/Domains/AuthDomain/Interface/UseCase/LogoutUseCase.swift
@@ -1,5 +1,5 @@
import RxSwift
-public protocol LogoutUseCase {
+public protocol LogoutUseCase: Sendable {
func execute(localOnly: Bool) -> Completable
}
diff --git a/Projects/Domains/AuthDomain/Interface/UseCase/ReGenerateAccessTokenUseCase.swift b/Projects/Domains/AuthDomain/Interface/UseCase/ReGenerateAccessTokenUseCase.swift
index 6daa03e4f..f32999e34 100644
--- a/Projects/Domains/AuthDomain/Interface/UseCase/ReGenerateAccessTokenUseCase.swift
+++ b/Projects/Domains/AuthDomain/Interface/UseCase/ReGenerateAccessTokenUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol ReGenerateAccessTokenUseCase {
+public protocol ReGenerateAccessTokenUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/AuthDomain/Testing/CheckIsExistAccessTokenUseCaseStub.swift b/Projects/Domains/AuthDomain/Testing/CheckIsExistAccessTokenUseCaseStub.swift
index 80bfb1c72..4eb9d0637 100644
--- a/Projects/Domains/AuthDomain/Testing/CheckIsExistAccessTokenUseCaseStub.swift
+++ b/Projects/Domains/AuthDomain/Testing/CheckIsExistAccessTokenUseCaseStub.swift
@@ -1,7 +1,7 @@
import AuthDomainInterface
import RxSwift
-public struct CheckIsExistAccessTokenUseCaseStub: CheckIsExistAccessTokenUseCase {
+public struct CheckIsExistAccessTokenUseCaseStub: CheckIsExistAccessTokenUseCase, @unchecked Sendable {
public func execute() -> Single {
return .just(false)
}
diff --git a/Projects/Domains/BaseDomain/Sources/BasePlugin/BasePlugin.swift b/Projects/Domains/BaseDomain/Sources/BasePlugin/BasePlugin.swift
index dc97392be..0d9b9680f 100644
--- a/Projects/Domains/BaseDomain/Sources/BasePlugin/BasePlugin.swift
+++ b/Projects/Domains/BaseDomain/Sources/BasePlugin/BasePlugin.swift
@@ -76,7 +76,16 @@ private extension BasePlugin {
func fetchDeviceID() -> String {
let deviceIDFromKeychain: String = keychain.load(type: .deviceID)
- let uuidString: String? = UIDevice.current.identifierForVendor?.uuidString
+ let uuidString: String?
+ if Thread.isMainThread {
+ uuidString = MainActor.assumeIsolated {
+ UIDevice.current.identifierForVendor?.uuidString
+ }
+ } else {
+ uuidString = DispatchQueue.main.sync {
+ UIDevice.current.identifierForVendor?.uuidString
+ }
+ }
if deviceIDFromKeychain.isEmpty, let uuidString {
keychain.save(type: .deviceID, value: uuidString)
diff --git a/Projects/Domains/BaseDomain/Sources/DataSource/BaseRemoteDataSource.swift b/Projects/Domains/BaseDomain/Sources/DataSource/BaseRemoteDataSource.swift
index ad03cb542..04fe073ea 100644
--- a/Projects/Domains/BaseDomain/Sources/DataSource/BaseRemoteDataSource.swift
+++ b/Projects/Domains/BaseDomain/Sources/DataSource/BaseRemoteDataSource.swift
@@ -8,14 +8,14 @@
import Foundation
import KeychainModule
-import Moya
-import RxMoya
+@preconcurrency import Moya
+@preconcurrency import RxMoya
import RxSwift
-open class BaseRemoteDataSource {
+open class BaseRemoteDataSource: @unchecked Sendable {
private let keychain: any Keychain
private let provider: MoyaProvider
- private var refreshProvider: MoyaProvider?
+ private let refreshProvider: MoyaProvider
private let decoder = JSONDecoder()
private let maxRetryCount = 2
@@ -31,11 +31,16 @@ open class BaseRemoteDataSource {
BasePlugin(keychain: keychain),
CustomLoggingPlugin()
])
+ self.refreshProvider = MoyaProvider(plugins: [
+ JwtPlugin(keychain: keychain),
+ CustomLoggingPlugin()
+ ])
#else
self.provider = provider ?? MoyaProvider(plugins: [
JwtPlugin(keychain: keychain),
BasePlugin(keychain: keychain)
])
+ self.refreshProvider = MoyaProvider(plugins: [JwtPlugin(keychain: keychain)])
#endif
}
@@ -107,20 +112,7 @@ private extension BaseRemoteDataSource {
}
func reissueToken() -> Completable {
- #if DEBUG || QA
- let provider = refreshProvider ?? MoyaProvider(plugins: [
- JwtPlugin(keychain: keychain),
- CustomLoggingPlugin()
- ])
- #else
- let provider = refreshProvider ?? MoyaProvider(plugins: [JwtPlugin(keychain: keychain)])
- #endif
-
- if refreshProvider == nil {
- refreshProvider = provider
- }
-
- return provider.rx.request(.refresh)
+ return refreshProvider.rx.request(.refresh)
.asCompletable()
}
}
diff --git a/Projects/Domains/ChartDomain/Interface/DataSource/RemoteChartDataSource.swift b/Projects/Domains/ChartDomain/Interface/DataSource/RemoteChartDataSource.swift
index 521e1feff..298f7332a 100644
--- a/Projects/Domains/ChartDomain/Interface/DataSource/RemoteChartDataSource.swift
+++ b/Projects/Domains/ChartDomain/Interface/DataSource/RemoteChartDataSource.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol RemoteChartDataSource {
+public protocol RemoteChartDataSource: Sendable {
func fetchChartRanking(type: ChartDateType) -> Single
func fetchCurrentVideoUseCase() -> Single
}
diff --git a/Projects/Domains/ChartDomain/Interface/Entity/CurrentVideoEntity.swift b/Projects/Domains/ChartDomain/Interface/Entity/CurrentVideoEntity.swift
index 26c35b0e9..7ae5d02cd 100644
--- a/Projects/Domains/ChartDomain/Interface/Entity/CurrentVideoEntity.swift
+++ b/Projects/Domains/ChartDomain/Interface/Entity/CurrentVideoEntity.swift
@@ -1,6 +1,6 @@
import Foundation
-public struct CurrentVideoEntity: Hashable {
+public struct CurrentVideoEntity: Hashable, Sendable {
public let id: String
public init(id: String) {
diff --git a/Projects/Domains/ChartDomain/Interface/Repository/ChartRepository.swift b/Projects/Domains/ChartDomain/Interface/Repository/ChartRepository.swift
index bef1aa8c6..29a67b0d6 100644
--- a/Projects/Domains/ChartDomain/Interface/Repository/ChartRepository.swift
+++ b/Projects/Domains/ChartDomain/Interface/Repository/ChartRepository.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol ChartRepository {
+public protocol ChartRepository: Sendable {
func fetchChartRanking(type: ChartDateType) -> Single
func fetchCurrentVideoUseCase() -> Single
}
diff --git a/Projects/Domains/ChartDomain/Interface/UseCase/FetchChartRankingUseCase.swift b/Projects/Domains/ChartDomain/Interface/UseCase/FetchChartRankingUseCase.swift
index 3093ee0d1..457aadc80 100644
--- a/Projects/Domains/ChartDomain/Interface/UseCase/FetchChartRankingUseCase.swift
+++ b/Projects/Domains/ChartDomain/Interface/UseCase/FetchChartRankingUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchChartRankingUseCase {
+public protocol FetchChartRankingUseCase: Sendable {
func execute(type: ChartDateType) -> Single
}
diff --git a/Projects/Domains/ChartDomain/Interface/UseCase/FetchCurrentVideoUseCase.swift b/Projects/Domains/ChartDomain/Interface/UseCase/FetchCurrentVideoUseCase.swift
index f04360eb6..9fcf5e347 100644
--- a/Projects/Domains/ChartDomain/Interface/UseCase/FetchCurrentVideoUseCase.swift
+++ b/Projects/Domains/ChartDomain/Interface/UseCase/FetchCurrentVideoUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchCurrentVideoUseCase {
+public protocol FetchCurrentVideoUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/CreditDomain/Interface/DataSource/RemoteCreditDataSource.swift b/Projects/Domains/CreditDomain/Interface/DataSource/RemoteCreditDataSource.swift
index fe8e6f884..1c7f69687 100644
--- a/Projects/Domains/CreditDomain/Interface/DataSource/RemoteCreditDataSource.swift
+++ b/Projects/Domains/CreditDomain/Interface/DataSource/RemoteCreditDataSource.swift
@@ -2,7 +2,7 @@ import Foundation
import RxSwift
import SongsDomainInterface
-public protocol RemoteCreditDataSource {
+public protocol RemoteCreditDataSource: Sendable {
func fetchCreditSongList(
name: String,
order: CreditSongOrderType,
diff --git a/Projects/Domains/CreditDomain/Interface/Repository/CreditRepository.swift b/Projects/Domains/CreditDomain/Interface/Repository/CreditRepository.swift
index ef3035664..c39c96630 100644
--- a/Projects/Domains/CreditDomain/Interface/Repository/CreditRepository.swift
+++ b/Projects/Domains/CreditDomain/Interface/Repository/CreditRepository.swift
@@ -2,7 +2,7 @@ import Foundation
import RxSwift
import SongsDomainInterface
-public protocol CreditRepository {
+public protocol CreditRepository: Sendable {
func fetchCreditSongList(
name: String,
order: CreditSongOrderType,
diff --git a/Projects/Domains/CreditDomain/Interface/UseCase/FetchCreditProfileUseCase.swift b/Projects/Domains/CreditDomain/Interface/UseCase/FetchCreditProfileUseCase.swift
index 5bec1b3b7..532b2bb04 100644
--- a/Projects/Domains/CreditDomain/Interface/UseCase/FetchCreditProfileUseCase.swift
+++ b/Projects/Domains/CreditDomain/Interface/UseCase/FetchCreditProfileUseCase.swift
@@ -1,5 +1,5 @@
import RxSwift
-public protocol FetchCreditProfileUseCase {
+public protocol FetchCreditProfileUseCase: Sendable {
func execute(name: String) -> Single
}
diff --git a/Projects/Domains/CreditDomain/Interface/UseCase/FetchCreditSongListUseCase.swift b/Projects/Domains/CreditDomain/Interface/UseCase/FetchCreditSongListUseCase.swift
index 3da792edd..4957ffd5b 100644
--- a/Projects/Domains/CreditDomain/Interface/UseCase/FetchCreditSongListUseCase.swift
+++ b/Projects/Domains/CreditDomain/Interface/UseCase/FetchCreditSongListUseCase.swift
@@ -2,7 +2,7 @@ import Foundation
import RxSwift
import SongsDomainInterface
-public protocol FetchCreditSongListUseCase {
+public protocol FetchCreditSongListUseCase: Sendable {
func execute(
name: String,
order: CreditSongOrderType,
diff --git a/Projects/Domains/CreditDomain/Testing/UseCase/FetchCreditProfileUseCaseSpy.swift b/Projects/Domains/CreditDomain/Testing/UseCase/FetchCreditProfileUseCaseSpy.swift
index fd207404c..395207515 100644
--- a/Projects/Domains/CreditDomain/Testing/UseCase/FetchCreditProfileUseCaseSpy.swift
+++ b/Projects/Domains/CreditDomain/Testing/UseCase/FetchCreditProfileUseCaseSpy.swift
@@ -2,7 +2,7 @@ import CreditDomainInterface
import RxSwift
import SongsDomainInterface
-public final class FetchCreditProfileUseCaseSpy: FetchCreditProfileUseCase {
+public final class FetchCreditProfileUseCaseSpy: FetchCreditProfileUseCase, @unchecked Sendable {
public var callCount = 0
public var handler: (String) -> Single = { _ in fatalError() }
diff --git a/Projects/Domains/CreditDomain/Testing/UseCase/FetchCreditSongListUseCaseSpy.swift b/Projects/Domains/CreditDomain/Testing/UseCase/FetchCreditSongListUseCaseSpy.swift
index 9dd5d72fe..2d08eb554 100644
--- a/Projects/Domains/CreditDomain/Testing/UseCase/FetchCreditSongListUseCaseSpy.swift
+++ b/Projects/Domains/CreditDomain/Testing/UseCase/FetchCreditSongListUseCaseSpy.swift
@@ -2,7 +2,7 @@ import CreditDomainInterface
import RxSwift
import SongsDomainInterface
-public final class FetchCreditSongListUseCaseSpy: FetchCreditSongListUseCase {
+public final class FetchCreditSongListUseCaseSpy: FetchCreditSongListUseCase, @unchecked Sendable {
public var callCount = 0
public var handler: (String, CreditSongOrderType, Int, Int) -> Single<[SongEntity]> = { _, _, _, _ in fatalError() }
diff --git a/Projects/Domains/FaqDomain/Interface/DataSource/RemoteFaqDataSource.swift b/Projects/Domains/FaqDomain/Interface/DataSource/RemoteFaqDataSource.swift
index bd5ef8d31..ed5c1c32b 100644
--- a/Projects/Domains/FaqDomain/Interface/DataSource/RemoteFaqDataSource.swift
+++ b/Projects/Domains/FaqDomain/Interface/DataSource/RemoteFaqDataSource.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol RemoteFaqDataSource {
+public protocol RemoteFaqDataSource: Sendable {
func fetchCategories() -> Single
func fetchQna() -> Single<[FaqEntity]>
}
diff --git a/Projects/Domains/FaqDomain/Interface/Repository/FaqRepository.swift b/Projects/Domains/FaqDomain/Interface/Repository/FaqRepository.swift
index d1d223ac8..2e5840ec8 100644
--- a/Projects/Domains/FaqDomain/Interface/Repository/FaqRepository.swift
+++ b/Projects/Domains/FaqDomain/Interface/Repository/FaqRepository.swift
@@ -9,7 +9,7 @@
import Foundation
import RxSwift
-public protocol FaqRepository {
+public protocol FaqRepository: Sendable {
func fetchQnaCategories() -> Single
func fetchQna() -> Single<[FaqEntity]>
}
diff --git a/Projects/Domains/FaqDomain/Interface/UseCase/FetchFaqCategoriesUseCase.swift b/Projects/Domains/FaqDomain/Interface/UseCase/FetchFaqCategoriesUseCase.swift
index 56b863ece..035314f13 100644
--- a/Projects/Domains/FaqDomain/Interface/UseCase/FetchFaqCategoriesUseCase.swift
+++ b/Projects/Domains/FaqDomain/Interface/UseCase/FetchFaqCategoriesUseCase.swift
@@ -9,6 +9,6 @@
import Foundation
import RxSwift
-public protocol FetchFaqCategoriesUseCase {
+public protocol FetchFaqCategoriesUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/FaqDomain/Interface/UseCase/FetchFaqUseCase.swift b/Projects/Domains/FaqDomain/Interface/UseCase/FetchFaqUseCase.swift
index 34ffb4b27..5fd0aebad 100644
--- a/Projects/Domains/FaqDomain/Interface/UseCase/FetchFaqUseCase.swift
+++ b/Projects/Domains/FaqDomain/Interface/UseCase/FetchFaqUseCase.swift
@@ -9,6 +9,6 @@
import Foundation
import RxSwift
-public protocol FetchFaqUseCase {
+public protocol FetchFaqUseCase: Sendable {
func execute() -> Single<[FaqEntity]>
}
diff --git a/Projects/Domains/FaqDomain/Testing/FetchFaqCategoriesUseCaseStub.swift b/Projects/Domains/FaqDomain/Testing/FetchFaqCategoriesUseCaseStub.swift
index c2c4d7aae..2a2621461 100644
--- a/Projects/Domains/FaqDomain/Testing/FetchFaqCategoriesUseCaseStub.swift
+++ b/Projects/Domains/FaqDomain/Testing/FetchFaqCategoriesUseCaseStub.swift
@@ -2,7 +2,7 @@ import FaqDomainInterface
import Foundation
import RxSwift
-public struct FetchFaqCategoriesUseCaseStub: FetchFaqCategoriesUseCase {
+public struct FetchFaqCategoriesUseCaseStub: FetchFaqCategoriesUseCase, @unchecked Sendable {
public func execute() -> Single {
return .just(FaqCategoryEntity(categories: []))
}
diff --git a/Projects/Domains/FaqDomain/Testing/FetchFaqUseCaseStub.swift b/Projects/Domains/FaqDomain/Testing/FetchFaqUseCaseStub.swift
index 329d37e71..48ea21a4b 100644
--- a/Projects/Domains/FaqDomain/Testing/FetchFaqUseCaseStub.swift
+++ b/Projects/Domains/FaqDomain/Testing/FetchFaqUseCaseStub.swift
@@ -2,7 +2,7 @@ import FaqDomainInterface
import Foundation
import RxSwift
-public struct FetchFaqUseCaseStub: FetchFaqUseCase {
+public struct FetchFaqUseCaseStub: FetchFaqUseCase, @unchecked Sendable {
public func execute() -> Single<[FaqEntity]> {
return .just([])
}
diff --git a/Projects/Domains/ImageDomain/Interface/DataSource/RemoteImageDataSource.swift b/Projects/Domains/ImageDomain/Interface/DataSource/RemoteImageDataSource.swift
index ef6eeb0da..ed4da48ea 100644
--- a/Projects/Domains/ImageDomain/Interface/DataSource/RemoteImageDataSource.swift
+++ b/Projects/Domains/ImageDomain/Interface/DataSource/RemoteImageDataSource.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol RemoteImageDataSource {
+public protocol RemoteImageDataSource: Sendable {
func fetchLyricDecoratingBackground() -> Single<[LyricDecoratingBackgroundEntity]>
func fetchProfileList() -> Single<[ProfileListEntity]>
func fetchDefaultPlaylistImage() -> Single<[DefaultImageEntity]>
diff --git a/Projects/Domains/ImageDomain/Interface/Entity/DefaultImageEntity.swift b/Projects/Domains/ImageDomain/Interface/Entity/DefaultImageEntity.swift
index 55003262b..2acdbd4e9 100644
--- a/Projects/Domains/ImageDomain/Interface/Entity/DefaultImageEntity.swift
+++ b/Projects/Domains/ImageDomain/Interface/Entity/DefaultImageEntity.swift
@@ -1,6 +1,6 @@
import Foundation
-public struct DefaultImageEntity: Hashable, Equatable {
+public struct DefaultImageEntity: Hashable, Equatable, Sendable {
public let name: String
public let url: String
diff --git a/Projects/Domains/ImageDomain/Interface/Repository/ImageRepository.swift b/Projects/Domains/ImageDomain/Interface/Repository/ImageRepository.swift
index ef3c8e41e..d7766d591 100644
--- a/Projects/Domains/ImageDomain/Interface/Repository/ImageRepository.swift
+++ b/Projects/Domains/ImageDomain/Interface/Repository/ImageRepository.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol ImageRepository {
+public protocol ImageRepository: Sendable {
func fetchLyricDecoratingBackground() -> Single<[LyricDecoratingBackgroundEntity]>
func fetchProfileList() -> Single<[ProfileListEntity]>
func fetchDefaultPlaylistImage() -> Single<[DefaultImageEntity]>
diff --git a/Projects/Domains/ImageDomain/Interface/UseCase/FetchDefaultPlaylistImageUseCase.swift b/Projects/Domains/ImageDomain/Interface/UseCase/FetchDefaultPlaylistImageUseCase.swift
index dca426e27..cf5bb3743 100644
--- a/Projects/Domains/ImageDomain/Interface/UseCase/FetchDefaultPlaylistImageUseCase.swift
+++ b/Projects/Domains/ImageDomain/Interface/UseCase/FetchDefaultPlaylistImageUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchDefaultPlaylistImageUseCase {
+public protocol FetchDefaultPlaylistImageUseCase: Sendable {
func execute() -> Single<[DefaultImageEntity]>
}
diff --git a/Projects/Domains/ImageDomain/Interface/UseCase/FetchLyricDecoratingBackgroundUseCase.swift b/Projects/Domains/ImageDomain/Interface/UseCase/FetchLyricDecoratingBackgroundUseCase.swift
index 6ea0fe745..d4097094c 100644
--- a/Projects/Domains/ImageDomain/Interface/UseCase/FetchLyricDecoratingBackgroundUseCase.swift
+++ b/Projects/Domains/ImageDomain/Interface/UseCase/FetchLyricDecoratingBackgroundUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchLyricDecoratingBackgroundUseCase {
+public protocol FetchLyricDecoratingBackgroundUseCase: Sendable {
func execute() -> Single<[LyricDecoratingBackgroundEntity]>
}
diff --git a/Projects/Domains/ImageDomain/Interface/UseCase/FetchProfileListUseCase.swift b/Projects/Domains/ImageDomain/Interface/UseCase/FetchProfileListUseCase.swift
index b16712279..bccddac1b 100644
--- a/Projects/Domains/ImageDomain/Interface/UseCase/FetchProfileListUseCase.swift
+++ b/Projects/Domains/ImageDomain/Interface/UseCase/FetchProfileListUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchProfileListUseCase {
+public protocol FetchProfileListUseCase: Sendable {
func execute() -> Single<[ProfileListEntity]>
}
diff --git a/Projects/Domains/LikeDomain/Interface/DataSource/RemoteLikeDataSource.swift b/Projects/Domains/LikeDomain/Interface/DataSource/RemoteLikeDataSource.swift
index 8937ba85d..b8dc9f0b2 100644
--- a/Projects/Domains/LikeDomain/Interface/DataSource/RemoteLikeDataSource.swift
+++ b/Projects/Domains/LikeDomain/Interface/DataSource/RemoteLikeDataSource.swift
@@ -9,7 +9,7 @@
import Foundation
import RxSwift
-public protocol RemoteLikeDataSource {
+public protocol RemoteLikeDataSource: Sendable {
func addLikeSong(id: String) -> Single
func cancelLikeSong(id: String) -> Single
func checkIsLikedSong(id: String) -> Single
diff --git a/Projects/Domains/LikeDomain/Interface/Repository/LikeRepository.swift b/Projects/Domains/LikeDomain/Interface/Repository/LikeRepository.swift
index d633eac31..afacc9793 100644
--- a/Projects/Domains/LikeDomain/Interface/Repository/LikeRepository.swift
+++ b/Projects/Domains/LikeDomain/Interface/Repository/LikeRepository.swift
@@ -9,7 +9,7 @@
import Foundation
import RxSwift
-public protocol LikeRepository {
+public protocol LikeRepository: Sendable {
func addLikeSong(id: String) -> Single
func cancelLikeSong(id: String) -> Single
func checkIsLikedSong(id: String) -> Single
diff --git a/Projects/Domains/LikeDomain/Interface/UseCase/AddLikeSongUseCase.swift b/Projects/Domains/LikeDomain/Interface/UseCase/AddLikeSongUseCase.swift
index 7fabbba89..623eebf68 100644
--- a/Projects/Domains/LikeDomain/Interface/UseCase/AddLikeSongUseCase.swift
+++ b/Projects/Domains/LikeDomain/Interface/UseCase/AddLikeSongUseCase.swift
@@ -9,6 +9,6 @@
import Foundation
import RxSwift
-public protocol AddLikeSongUseCase {
+public protocol AddLikeSongUseCase: Sendable {
func execute(id: String) -> Single
}
diff --git a/Projects/Domains/LikeDomain/Interface/UseCase/CancelLikeSongUseCase.swift b/Projects/Domains/LikeDomain/Interface/UseCase/CancelLikeSongUseCase.swift
index 974a3e2b3..89f8da227 100644
--- a/Projects/Domains/LikeDomain/Interface/UseCase/CancelLikeSongUseCase.swift
+++ b/Projects/Domains/LikeDomain/Interface/UseCase/CancelLikeSongUseCase.swift
@@ -9,6 +9,6 @@
import Foundation
import RxSwift
-public protocol CancelLikeSongUseCase {
+public protocol CancelLikeSongUseCase: Sendable {
func execute(id: String) -> Single
}
diff --git a/Projects/Domains/LikeDomain/Testing/UseCase/AddLikeSongUseCaseSpy.swift b/Projects/Domains/LikeDomain/Testing/UseCase/AddLikeSongUseCaseSpy.swift
index ff041e1c3..bded15795 100644
--- a/Projects/Domains/LikeDomain/Testing/UseCase/AddLikeSongUseCaseSpy.swift
+++ b/Projects/Domains/LikeDomain/Testing/UseCase/AddLikeSongUseCaseSpy.swift
@@ -1,7 +1,7 @@
import LikeDomainInterface
import RxSwift
-public final class AddLikeSongUseCaseSpy: AddLikeSongUseCase {
+public final class AddLikeSongUseCaseSpy: AddLikeSongUseCase, @unchecked Sendable {
public private(set) var callCount = 0
public var handler: (String) -> Single = { _ in fatalError() }
diff --git a/Projects/Domains/LikeDomain/Testing/UseCase/CancelLikeSongUseCaseSpy.swift b/Projects/Domains/LikeDomain/Testing/UseCase/CancelLikeSongUseCaseSpy.swift
index 180422887..668144292 100644
--- a/Projects/Domains/LikeDomain/Testing/UseCase/CancelLikeSongUseCaseSpy.swift
+++ b/Projects/Domains/LikeDomain/Testing/UseCase/CancelLikeSongUseCaseSpy.swift
@@ -1,7 +1,7 @@
import LikeDomainInterface
import RxSwift
-public final class CancelLikeSongUseCaseSpy: CancelLikeSongUseCase {
+public final class CancelLikeSongUseCaseSpy: CancelLikeSongUseCase, @unchecked Sendable {
public private(set) var callCount = 0
public var handler: (String) -> Single = { _ in fatalError() }
diff --git a/Projects/Domains/NoticeDomain/Interface/DataSource/RemoteNoticeDataSource.swift b/Projects/Domains/NoticeDomain/Interface/DataSource/RemoteNoticeDataSource.swift
index 078a30721..fc4ac8e93 100644
--- a/Projects/Domains/NoticeDomain/Interface/DataSource/RemoteNoticeDataSource.swift
+++ b/Projects/Domains/NoticeDomain/Interface/DataSource/RemoteNoticeDataSource.swift
@@ -9,7 +9,7 @@
import Foundation
import RxSwift
-public protocol RemoteNoticeDataSource {
+public protocol RemoteNoticeDataSource: Sendable {
func fetchNoticeCategories() -> Single
func fetchNoticePopup() -> Single<[FetchNoticeEntity]>
func fetchNoticeAll() -> Single<[FetchNoticeEntity]>
diff --git a/Projects/Domains/NoticeDomain/Interface/Repository/NoticeRepository.swift b/Projects/Domains/NoticeDomain/Interface/Repository/NoticeRepository.swift
index 0755628b7..1153826e7 100644
--- a/Projects/Domains/NoticeDomain/Interface/Repository/NoticeRepository.swift
+++ b/Projects/Domains/NoticeDomain/Interface/Repository/NoticeRepository.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol NoticeRepository {
+public protocol NoticeRepository: Sendable {
func fetchNoticeCategories() -> Single
func fetchNoticePopup() -> Single<[FetchNoticeEntity]>
func fetchNoticeAll() -> Single<[FetchNoticeEntity]>
diff --git a/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeAllUseCase.swift b/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeAllUseCase.swift
index 740d5eae9..2f8167829 100644
--- a/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeAllUseCase.swift
+++ b/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeAllUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchNoticeAllUseCase {
+public protocol FetchNoticeAllUseCase: Sendable {
func execute() -> Single<[FetchNoticeEntity]>
}
diff --git a/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeCategoriesUseCase.swift b/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeCategoriesUseCase.swift
index f85908f3d..e8d4f412b 100644
--- a/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeCategoriesUseCase.swift
+++ b/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeCategoriesUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchNoticeCategoriesUseCase {
+public protocol FetchNoticeCategoriesUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeIDListUseCase.swift b/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeIDListUseCase.swift
index f89096fd3..02681a42c 100644
--- a/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeIDListUseCase.swift
+++ b/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticeIDListUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchNoticeIDListUseCase {
+public protocol FetchNoticeIDListUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticePopupUseCase.swift b/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticePopupUseCase.swift
index 4323ef4a3..48fd0fff4 100644
--- a/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticePopupUseCase.swift
+++ b/Projects/Domains/NoticeDomain/Interface/UseCase/FetchNoticePopupUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchNoticePopupUseCase {
+public protocol FetchNoticePopupUseCase: Sendable {
func execute() -> Single<[FetchNoticeEntity]>
}
diff --git a/Projects/Domains/NoticeDomain/Testing/FetchNoticeAllUseCaseStub.swift b/Projects/Domains/NoticeDomain/Testing/FetchNoticeAllUseCaseStub.swift
index 80389e2f7..8191d9632 100644
--- a/Projects/Domains/NoticeDomain/Testing/FetchNoticeAllUseCaseStub.swift
+++ b/Projects/Domains/NoticeDomain/Testing/FetchNoticeAllUseCaseStub.swift
@@ -2,7 +2,7 @@ import Foundation
import NoticeDomainInterface
import RxSwift
-public struct FetchNoticeAllUseCaseStub: FetchNoticeAllUseCase {
+public struct FetchNoticeAllUseCaseStub: FetchNoticeAllUseCase, @unchecked Sendable {
public func execute() -> Single<[FetchNoticeEntity]> {
let title1 = "๊ณต์ง์ฌํญ ๋์ค์ธ ๊ฒฝ์ฐ ๊ณต์ง์ฌํญ ๋์ค์ธ ๊ฒฝ์ฐ ๊ณต์ง์ฌํญ ๋์ค์ธ ๊ฒฝ์ฐ ๊ณต์ง์ฌํญ ๋์ค์ธ ๊ฒฝ์ฐ"
let title2 = "์ํ๋ฒ์ค ๋ฎค์ง 2.0 ์
๋ฐ์ดํธ"
diff --git a/Projects/Domains/NoticeDomain/Testing/FetchNoticeCategoriesUseCaseStub.swift b/Projects/Domains/NoticeDomain/Testing/FetchNoticeCategoriesUseCaseStub.swift
index 27833b9d0..7884de60f 100644
--- a/Projects/Domains/NoticeDomain/Testing/FetchNoticeCategoriesUseCaseStub.swift
+++ b/Projects/Domains/NoticeDomain/Testing/FetchNoticeCategoriesUseCaseStub.swift
@@ -2,7 +2,7 @@ import Foundation
import NoticeDomainInterface
import RxSwift
-public struct FetchNoticeCategoriesUseCaseStub: FetchNoticeCategoriesUseCase {
+public struct FetchNoticeCategoriesUseCaseStub: FetchNoticeCategoriesUseCase, @unchecked Sendable {
public func execute() -> Single {
return .just(FetchNoticeCategoriesEntity(categories: []))
}
diff --git a/Projects/Domains/NotificationDomain/Interface/DataSource/RemoteNotificationDataSource.swift b/Projects/Domains/NotificationDomain/Interface/DataSource/RemoteNotificationDataSource.swift
index 8b1c6224c..5989c4ac8 100644
--- a/Projects/Domains/NotificationDomain/Interface/DataSource/RemoteNotificationDataSource.swift
+++ b/Projects/Domains/NotificationDomain/Interface/DataSource/RemoteNotificationDataSource.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol RemoteNotificationDataSource {
+public protocol RemoteNotificationDataSource: Sendable {
func updateNotificationToken(type: NotificationUpdateType) -> Completable
}
diff --git a/Projects/Domains/NotificationDomain/Interface/Repository/NotificationRepository.swift b/Projects/Domains/NotificationDomain/Interface/Repository/NotificationRepository.swift
index 9f697805a..acbe9f3f7 100644
--- a/Projects/Domains/NotificationDomain/Interface/Repository/NotificationRepository.swift
+++ b/Projects/Domains/NotificationDomain/Interface/Repository/NotificationRepository.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol NotificationRepository {
+public protocol NotificationRepository: Sendable {
func updateNotificationToken(type: NotificationUpdateType) -> Completable
}
diff --git a/Projects/Domains/NotificationDomain/Interface/UseCase/UpdateNotificationTokenUseCase.swift b/Projects/Domains/NotificationDomain/Interface/UseCase/UpdateNotificationTokenUseCase.swift
index fd6e268a8..04f8300a1 100644
--- a/Projects/Domains/NotificationDomain/Interface/UseCase/UpdateNotificationTokenUseCase.swift
+++ b/Projects/Domains/NotificationDomain/Interface/UseCase/UpdateNotificationTokenUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol UpdateNotificationTokenUseCase {
+public protocol UpdateNotificationTokenUseCase: Sendable {
func execute(type: NotificationUpdateType) -> Completable
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/DataSource/RemotePlaylistDataSource.swift b/Projects/Domains/PlaylistDomain/Interface/DataSource/RemotePlaylistDataSource.swift
index b4130c423..55f3ffb56 100644
--- a/Projects/Domains/PlaylistDomain/Interface/DataSource/RemotePlaylistDataSource.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/DataSource/RemotePlaylistDataSource.swift
@@ -3,7 +3,7 @@ import Foundation
import RxSwift
import SongsDomainInterface
-public protocol RemotePlaylistDataSource {
+public protocol RemotePlaylistDataSource: Sendable {
func fetchRecommendPlaylist() -> Single<[RecommendPlaylistEntity]>
func fetchPlaylistDetail(id: String, type: PlaylistType) -> Single
func fetchWMPlaylistDetail(id: String) -> Single
diff --git a/Projects/Domains/PlaylistDomain/Interface/Entity/RecommendPlaylistEntity.swift b/Projects/Domains/PlaylistDomain/Interface/Entity/RecommendPlaylistEntity.swift
index 7fdcb15c4..f69474754 100644
--- a/Projects/Domains/PlaylistDomain/Interface/Entity/RecommendPlaylistEntity.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/Entity/RecommendPlaylistEntity.swift
@@ -1,6 +1,6 @@
import Foundation
-public struct RecommendPlaylistEntity: Hashable, Equatable {
+public struct RecommendPlaylistEntity: Hashable, Equatable, Sendable {
public init(
key: String,
title: String,
diff --git a/Projects/Domains/PlaylistDomain/Interface/Repository/PlaylistRepository.swift b/Projects/Domains/PlaylistDomain/Interface/Repository/PlaylistRepository.swift
index c8d0e9eea..2999a3074 100644
--- a/Projects/Domains/PlaylistDomain/Interface/Repository/PlaylistRepository.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/Repository/PlaylistRepository.swift
@@ -3,7 +3,7 @@ import Foundation
import RxSwift
import SongsDomainInterface
-public protocol PlaylistRepository {
+public protocol PlaylistRepository: Sendable {
func fetchRecommendPlaylist() -> Single<[RecommendPlaylistEntity]>
func fetchPlaylistDetail(id: String, type: PlaylistType) -> Single
func fetchWMPlaylistDetail(id: String) -> Single
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/AddSongIntoPlaylistUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/AddSongIntoPlaylistUseCase.swift
index ef690e71c..1110eb83c 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/AddSongIntoPlaylistUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/AddSongIntoPlaylistUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol AddSongIntoPlaylistUseCase {
+public protocol AddSongIntoPlaylistUseCase: Sendable {
func execute(key: String, songs: [String]) -> Single
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/CheckSubscriptionUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/CheckSubscriptionUseCase.swift
index 8a0c9bc3a..9070f836c 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/CheckSubscriptionUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/CheckSubscriptionUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol CheckSubscriptionUseCase {
+public protocol CheckSubscriptionUseCase: Sendable {
func execute(key: String) -> Single
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/CreatePlaylistUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/CreatePlaylistUseCase.swift
index b7b6f146a..6489b2bab 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/CreatePlaylistUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/CreatePlaylistUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol CreatePlaylistUseCase {
+public protocol CreatePlaylistUseCase: Sendable {
func execute(title: String) -> Single
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchPlaylistDetailUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchPlaylistDetailUseCase.swift
index eb15b13a8..d29484c72 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchPlaylistDetailUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchPlaylistDetailUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchPlaylistDetailUseCase {
+public protocol FetchPlaylistDetailUseCase: Sendable {
func execute(id: String, type: PlaylistType) -> Single
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchPlaylistSongsUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchPlaylistSongsUseCase.swift
index fc32cc722..a0a55fd63 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchPlaylistSongsUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchPlaylistSongsUseCase.swift
@@ -3,6 +3,6 @@ import Foundation
import RxSwift
import SongsDomainInterface
-public protocol FetchPlaylistSongsUseCase {
+public protocol FetchPlaylistSongsUseCase: Sendable {
func execute(key: String) -> Single<[SongEntity]>
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchRecommendPlaylistUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchRecommendPlaylistUseCase.swift
index 292d15ae9..f5d761df2 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchRecommendPlaylistUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchRecommendPlaylistUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchRecommendPlaylistUseCase {
+public protocol FetchRecommendPlaylistUseCase: Sendable {
func execute() -> Single<[RecommendPlaylistEntity]>
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchWMPlaylistDetailUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchWMPlaylistDetailUseCase.swift
index 4f3a3ad50..ce45a4244 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchWMPlaylistDetailUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/FetchWMPlaylistDetailUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchWMPlaylistDetailUseCase {
+public protocol FetchWMPlaylistDetailUseCase: Sendable {
func execute(id: String) -> Single
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/RemoveSongsUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/RemoveSongsUseCase.swift
index 43d13f61b..700254ffb 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/RemoveSongsUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/RemoveSongsUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol RemoveSongsUseCase {
+public protocol RemoveSongsUseCase: Sendable {
func execute(key: String, songs: [String]) -> Completable
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/RequestCustomImageURLUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/RequestCustomImageURLUseCase.swift
index df1db7d84..945397943 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/RequestCustomImageURLUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/RequestCustomImageURLUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol RequestCustomImageURLUseCase {
+public protocol RequestCustomImageURLUseCase: Sendable {
func execute(key: String, data: Data) -> Completable
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/RequestPlaylistOwnerIDUsecase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/RequestPlaylistOwnerIDUsecase.swift
index 2226011db..90be5331c 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/RequestPlaylistOwnerIDUsecase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/RequestPlaylistOwnerIDUsecase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol RequestPlaylistOwnerIDUsecase {
+public protocol RequestPlaylistOwnerIDUsecase: Sendable {
func execute(key: String) -> Single
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/SubscribePlaylistUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/SubscribePlaylistUseCase.swift
index 3e3707c0e..be6c88449 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/SubscribePlaylistUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/SubscribePlaylistUseCase.swift
@@ -1,5 +1,5 @@
import RxSwift
-public protocol SubscribePlaylistUseCase {
+public protocol SubscribePlaylistUseCase: Sendable {
func execute(key: String, isSubscribing: Bool) -> Completable
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/UpdatePlaylistUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/UpdatePlaylistUseCase.swift
index 043199681..2984787da 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/UpdatePlaylistUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/UpdatePlaylistUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol UpdatePlaylistUseCase {
+public protocol UpdatePlaylistUseCase: Sendable {
func execute(key: String, songs: [String]) -> Completable
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/UpdateTitleAndPrivateUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/UpdateTitleAndPrivateUseCase.swift
index d86527627..b9a2a8892 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/UpdateTitleAndPrivateUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/UpdateTitleAndPrivateUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol UpdateTitleAndPrivateUseCase {
+public protocol UpdateTitleAndPrivateUseCase: Sendable {
func execute(key: String, title: String?, isPrivate: Bool?) -> Completable
}
diff --git a/Projects/Domains/PlaylistDomain/Interface/UseCase/UploadPlaylistImageUseCase.swift b/Projects/Domains/PlaylistDomain/Interface/UseCase/UploadPlaylistImageUseCase.swift
index afead3e3b..fd55eb51e 100644
--- a/Projects/Domains/PlaylistDomain/Interface/UseCase/UploadPlaylistImageUseCase.swift
+++ b/Projects/Domains/PlaylistDomain/Interface/UseCase/UploadPlaylistImageUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol UploadDefaultPlaylistImageUseCase {
+public protocol UploadDefaultPlaylistImageUseCase: Sendable {
func execute(key: String, model: String) -> Completable
}
diff --git a/Projects/Domains/PlaylistDomain/Testing/FetchPlayListUseCaseStub.swift b/Projects/Domains/PlaylistDomain/Testing/FetchPlayListUseCaseStub.swift
index f8a0dffa8..fbdb036fc 100644
--- a/Projects/Domains/PlaylistDomain/Testing/FetchPlayListUseCaseStub.swift
+++ b/Projects/Domains/PlaylistDomain/Testing/FetchPlayListUseCaseStub.swift
@@ -1,7 +1,7 @@
import PlaylistDomainInterface
import RxSwift
-final class FetchPlayListUseCaseStub: FetchRecommendPlaylistUseCase {
+final class FetchPlayListUseCaseStub: FetchRecommendPlaylistUseCase, @unchecked Sendable {
var fetchData = [
RecommendPlaylistEntity(
key: "best",
diff --git a/Projects/Domains/PriceDomain/Interface/DataSource/RemotePriceDataSource.swift b/Projects/Domains/PriceDomain/Interface/DataSource/RemotePriceDataSource.swift
index c938b5170..77c51baa9 100644
--- a/Projects/Domains/PriceDomain/Interface/DataSource/RemotePriceDataSource.swift
+++ b/Projects/Domains/PriceDomain/Interface/DataSource/RemotePriceDataSource.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol RemotePriceDataSource {
+public protocol RemotePriceDataSource: Sendable {
func fetchPlaylistCreationPrice() -> Single
func fetchPlaylistImagePrice() -> Single
}
diff --git a/Projects/Domains/PriceDomain/Interface/Repository/PriceRepository.swift b/Projects/Domains/PriceDomain/Interface/Repository/PriceRepository.swift
index 455ccaf04..77abe6784 100644
--- a/Projects/Domains/PriceDomain/Interface/Repository/PriceRepository.swift
+++ b/Projects/Domains/PriceDomain/Interface/Repository/PriceRepository.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol PriceRepository {
+public protocol PriceRepository: Sendable {
func fetchPlaylistCreationPrice() -> Single
func fetchPlaylistImagePrice() -> Single
}
diff --git a/Projects/Domains/PriceDomain/Interface/UseCase/FetchPlaylistCreationPriceUseCase.swift b/Projects/Domains/PriceDomain/Interface/UseCase/FetchPlaylistCreationPriceUseCase.swift
index 3a8d94c30..ab9813a99 100644
--- a/Projects/Domains/PriceDomain/Interface/UseCase/FetchPlaylistCreationPriceUseCase.swift
+++ b/Projects/Domains/PriceDomain/Interface/UseCase/FetchPlaylistCreationPriceUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchPlaylistCreationPriceUseCase {
+public protocol FetchPlaylistCreationPriceUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/PriceDomain/Interface/UseCase/FetchPlaylistImagePriceUseCase.swift b/Projects/Domains/PriceDomain/Interface/UseCase/FetchPlaylistImagePriceUseCase.swift
index 5fe52649a..655db9f38 100644
--- a/Projects/Domains/PriceDomain/Interface/UseCase/FetchPlaylistImagePriceUseCase.swift
+++ b/Projects/Domains/PriceDomain/Interface/UseCase/FetchPlaylistImagePriceUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchPlaylistImagePriceUseCase {
+public protocol FetchPlaylistImagePriceUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/SearchDomain/Interface/DataSource/RemoteSearchDataSource.swift b/Projects/Domains/SearchDomain/Interface/DataSource/RemoteSearchDataSource.swift
index 23b1c6237..f4f22e93f 100644
--- a/Projects/Domains/SearchDomain/Interface/DataSource/RemoteSearchDataSource.swift
+++ b/Projects/Domains/SearchDomain/Interface/DataSource/RemoteSearchDataSource.swift
@@ -3,7 +3,7 @@ import Foundation
import RxSwift
import SongsDomainInterface
-public protocol RemoteSearchDataSource {
+public protocol RemoteSearchDataSource: Sendable {
func fetchSearchSongs(order: SortType, filter: FilterType, text: String, page: Int, limit: Int)
-> Single<[SongEntity]>
func fetchSearchPlaylist(order: SortType, text: String, page: Int, limit: Int) -> Single<[SearchPlaylistEntity]>
diff --git a/Projects/Domains/SearchDomain/Interface/Entity/SearchPlaylistEntity.swift b/Projects/Domains/SearchDomain/Interface/Entity/SearchPlaylistEntity.swift
index 978a95464..98e1af630 100644
--- a/Projects/Domains/SearchDomain/Interface/Entity/SearchPlaylistEntity.swift
+++ b/Projects/Domains/SearchDomain/Interface/Entity/SearchPlaylistEntity.swift
@@ -1,6 +1,6 @@
import Foundation
-public struct SearchPlaylistEntity: Hashable, Equatable {
+public struct SearchPlaylistEntity: Hashable, Equatable, Sendable {
public init(
key: String,
title: String,
diff --git a/Projects/Domains/SearchDomain/Interface/Enum/Option.swift b/Projects/Domains/SearchDomain/Interface/Enum/Option.swift
index bee7fa6ea..0e1706928 100644
--- a/Projects/Domains/SearchDomain/Interface/Enum/Option.swift
+++ b/Projects/Domains/SearchDomain/Interface/Enum/Option.swift
@@ -2,7 +2,7 @@ public protocol SearchOptionType {
var title: String { get }
}
-public enum FilterType: String, Encodable, SearchOptionType {
+public enum FilterType: String, Encodable, SearchOptionType, Sendable {
case all
case title
case artist
@@ -22,7 +22,7 @@ public enum FilterType: String, Encodable, SearchOptionType {
}
}
-public enum SortType: String, Encodable, SearchOptionType {
+public enum SortType: String, Encodable, SearchOptionType, Sendable {
case latest
case oldest
case relevance
diff --git a/Projects/Domains/SearchDomain/Interface/Repository/SearchRepository.swift b/Projects/Domains/SearchDomain/Interface/Repository/SearchRepository.swift
index 9f14eef76..d15e97eda 100644
--- a/Projects/Domains/SearchDomain/Interface/Repository/SearchRepository.swift
+++ b/Projects/Domains/SearchDomain/Interface/Repository/SearchRepository.swift
@@ -3,7 +3,7 @@ import Foundation
import RxSwift
import SongsDomainInterface
-public protocol SearchRepository {
+public protocol SearchRepository: Sendable {
func fetchSearchSongs(order: SortType, filter: FilterType, text: String, page: Int, limit: Int)
-> Single<[SongEntity]>
func fetchSearchPlaylist(order: SortType, text: String, page: Int, limit: Int) -> Single<[SearchPlaylistEntity]>
diff --git a/Projects/Domains/SearchDomain/Interface/UseCase/FetchSearchPlaylistsUseCase.swift b/Projects/Domains/SearchDomain/Interface/UseCase/FetchSearchPlaylistsUseCase.swift
index f943f8108..674e14a61 100644
--- a/Projects/Domains/SearchDomain/Interface/UseCase/FetchSearchPlaylistsUseCase.swift
+++ b/Projects/Domains/SearchDomain/Interface/UseCase/FetchSearchPlaylistsUseCase.swift
@@ -2,6 +2,6 @@ import Foundation
import PlaylistDomainInterface
import RxSwift
-public protocol FetchSearchPlaylistsUseCase {
+public protocol FetchSearchPlaylistsUseCase: Sendable {
func execute(order: SortType, text: String, page: Int, limit: Int) -> Single<[SearchPlaylistEntity]>
}
diff --git a/Projects/Domains/SearchDomain/Interface/UseCase/FetchSearchSongsUseCase.swift b/Projects/Domains/SearchDomain/Interface/UseCase/FetchSearchSongsUseCase.swift
index 3fb83c108..e281c0b7a 100644
--- a/Projects/Domains/SearchDomain/Interface/UseCase/FetchSearchSongsUseCase.swift
+++ b/Projects/Domains/SearchDomain/Interface/UseCase/FetchSearchSongsUseCase.swift
@@ -2,6 +2,6 @@ import Foundation
import RxSwift
import SongsDomainInterface
-public protocol FetchSearchSongsUseCase {
+public protocol FetchSearchSongsUseCase: Sendable {
func execute(order: SortType, filter: FilterType, text: String, page: Int, limit: Int) -> Single<[SongEntity]>
}
diff --git a/Projects/Domains/SongsDomain/Interface/DataSource/RemoteSongsDataSource.swift b/Projects/Domains/SongsDomain/Interface/DataSource/RemoteSongsDataSource.swift
index a71466d11..cc1f3c5bd 100644
--- a/Projects/Domains/SongsDomain/Interface/DataSource/RemoteSongsDataSource.swift
+++ b/Projects/Domains/SongsDomain/Interface/DataSource/RemoteSongsDataSource.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol RemoteSongsDataSource {
+public protocol RemoteSongsDataSource: Sendable {
func fetchSong(id: String) -> Single
func fetchLyrics(id: String) -> Single
func fetchSongCredits(id: String) -> Single<[SongCreditsEntity]>
diff --git a/Projects/Domains/SongsDomain/Interface/Entity/SongDetailEntity.swift b/Projects/Domains/SongsDomain/Interface/Entity/SongDetailEntity.swift
index 04d484828..36e51143f 100644
--- a/Projects/Domains/SongsDomain/Interface/Entity/SongDetailEntity.swift
+++ b/Projects/Domains/SongsDomain/Interface/Entity/SongDetailEntity.swift
@@ -1,6 +1,6 @@
import Foundation
-public struct SongDetailEntity: Hashable {
+public struct SongDetailEntity: Hashable, Sendable {
public init(
id: String,
title: String,
@@ -28,7 +28,7 @@ public struct SongDetailEntity: Hashable {
public let isLiked: Bool
public let karaokeNumber: SongDetailEntity.KaraokeNumber
- public struct KaraokeNumber: Hashable, Equatable {
+ public struct KaraokeNumber: Hashable, Equatable, Sendable {
public init (tj: Int?, ky: Int?) {
self.tj = tj
self.ky = ky
diff --git a/Projects/Domains/SongsDomain/Interface/Entity/SongEntity.swift b/Projects/Domains/SongsDomain/Interface/Entity/SongEntity.swift
index b4f20862d..945567caf 100644
--- a/Projects/Domains/SongsDomain/Interface/Entity/SongEntity.swift
+++ b/Projects/Domains/SongsDomain/Interface/Entity/SongEntity.swift
@@ -1,6 +1,9 @@
import Foundation
-public struct SongEntity: Hashable {
+/**
+ isSelected๊ฐ mutable์ด๋ sendableํ์ง ๋ชปํจ.
+ */
+public struct SongEntity: Hashable, @unchecked Sendable {
public init(
id: String,
title: String,
diff --git a/Projects/Domains/SongsDomain/Interface/Repository/SongsRepository.swift b/Projects/Domains/SongsDomain/Interface/Repository/SongsRepository.swift
index ffeafca85..6f81438f2 100644
--- a/Projects/Domains/SongsDomain/Interface/Repository/SongsRepository.swift
+++ b/Projects/Domains/SongsDomain/Interface/Repository/SongsRepository.swift
@@ -1,7 +1,7 @@
import Foundation
import RxSwift
-public protocol SongsRepository {
+public protocol SongsRepository: Sendable {
func fetchSong(id: String) -> Single
func fetchLyrics(id: String) -> Single
func fetchSongCredits(id: String) -> Single<[SongCreditsEntity]>
diff --git a/Projects/Domains/SongsDomain/Interface/UseCase/FetchLyricsUseCase.swift b/Projects/Domains/SongsDomain/Interface/UseCase/FetchLyricsUseCase.swift
index 7cc1b8fe1..6aff8a65e 100644
--- a/Projects/Domains/SongsDomain/Interface/UseCase/FetchLyricsUseCase.swift
+++ b/Projects/Domains/SongsDomain/Interface/UseCase/FetchLyricsUseCase.swift
@@ -9,6 +9,6 @@
import Foundation
import RxSwift
-public protocol FetchLyricsUseCase {
+public protocol FetchLyricsUseCase: Sendable {
func execute(id: String) -> Single
}
diff --git a/Projects/Domains/SongsDomain/Interface/UseCase/FetchNewSongsPlaylistUseCase.swift b/Projects/Domains/SongsDomain/Interface/UseCase/FetchNewSongsPlaylistUseCase.swift
index d32c9ff5c..b5ce06d0f 100644
--- a/Projects/Domains/SongsDomain/Interface/UseCase/FetchNewSongsPlaylistUseCase.swift
+++ b/Projects/Domains/SongsDomain/Interface/UseCase/FetchNewSongsPlaylistUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchNewSongsPlaylistUseCase {
+public protocol FetchNewSongsPlaylistUseCase: Sendable {
func execute(type: NewSongGroupType) -> Single
}
diff --git a/Projects/Domains/SongsDomain/Interface/UseCase/FetchNewSongsUseCase.swift b/Projects/Domains/SongsDomain/Interface/UseCase/FetchNewSongsUseCase.swift
index 379030e45..7e6d952f7 100644
--- a/Projects/Domains/SongsDomain/Interface/UseCase/FetchNewSongsUseCase.swift
+++ b/Projects/Domains/SongsDomain/Interface/UseCase/FetchNewSongsUseCase.swift
@@ -9,6 +9,6 @@
import Foundation
import RxSwift
-public protocol FetchNewSongsUseCase {
+public protocol FetchNewSongsUseCase: Sendable {
func execute(type: NewSongGroupType, page: Int, limit: Int) -> Single<[NewSongsEntity]>
}
diff --git a/Projects/Domains/SongsDomain/Interface/UseCase/FetchSongCreditsUseCase.swift b/Projects/Domains/SongsDomain/Interface/UseCase/FetchSongCreditsUseCase.swift
index 716227c6b..7baf4cb03 100644
--- a/Projects/Domains/SongsDomain/Interface/UseCase/FetchSongCreditsUseCase.swift
+++ b/Projects/Domains/SongsDomain/Interface/UseCase/FetchSongCreditsUseCase.swift
@@ -9,6 +9,6 @@
import Foundation
import RxSwift
-public protocol FetchSongCreditsUseCase {
+public protocol FetchSongCreditsUseCase: Sendable {
func execute(id: String) -> Single<[SongCreditsEntity]>
}
diff --git a/Projects/Domains/SongsDomain/Interface/UseCase/FetchSongUseCase.swift b/Projects/Domains/SongsDomain/Interface/UseCase/FetchSongUseCase.swift
index c4a2c81d2..a1b5b27b5 100644
--- a/Projects/Domains/SongsDomain/Interface/UseCase/FetchSongUseCase.swift
+++ b/Projects/Domains/SongsDomain/Interface/UseCase/FetchSongUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchSongUseCase {
+public protocol FetchSongUseCase: Sendable {
func execute(id: String) -> Single
}
diff --git a/Projects/Domains/SongsDomain/Testing/UseCase/FetchSongCreditsUseCaseSpy.swift b/Projects/Domains/SongsDomain/Testing/UseCase/FetchSongCreditsUseCaseSpy.swift
index 7e26eee22..bb7007207 100644
--- a/Projects/Domains/SongsDomain/Testing/UseCase/FetchSongCreditsUseCaseSpy.swift
+++ b/Projects/Domains/SongsDomain/Testing/UseCase/FetchSongCreditsUseCaseSpy.swift
@@ -1,7 +1,7 @@
import RxSwift
import SongsDomainInterface
-public final class FetchSongCreditsUseCaseSpy: FetchSongCreditsUseCase {
+public final class FetchSongCreditsUseCaseSpy: FetchSongCreditsUseCase, @unchecked Sendable {
public private(set) var callCount = 0
public var handler: ((String) -> Single<[SongCreditsEntity]>) = { _ in fatalError() }
diff --git a/Projects/Domains/SongsDomain/Testing/UseCase/FetchSongUseCaseSpy.swift b/Projects/Domains/SongsDomain/Testing/UseCase/FetchSongUseCaseSpy.swift
index 5642fb95b..e344d4849 100644
--- a/Projects/Domains/SongsDomain/Testing/UseCase/FetchSongUseCaseSpy.swift
+++ b/Projects/Domains/SongsDomain/Testing/UseCase/FetchSongUseCaseSpy.swift
@@ -1,7 +1,7 @@
import RxSwift
import SongsDomainInterface
-public final class FetchSongUseCaseSpy: FetchSongUseCase {
+public final class FetchSongUseCaseSpy: FetchSongUseCase, @unchecked Sendable {
public private(set) var callCount = 0
public var handler: ((String) -> Single) = { _ in fatalError() }
diff --git a/Projects/Domains/TeamDomain/Interface/DataSource/RemoteTeamDataSource.swift b/Projects/Domains/TeamDomain/Interface/DataSource/RemoteTeamDataSource.swift
index 83fd547f2..212c71600 100644
--- a/Projects/Domains/TeamDomain/Interface/DataSource/RemoteTeamDataSource.swift
+++ b/Projects/Domains/TeamDomain/Interface/DataSource/RemoteTeamDataSource.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol RemoteTeamDataSource {
+public protocol RemoteTeamDataSource: Sendable {
func fetchTeamList() -> Single<[TeamListEntity]>
}
diff --git a/Projects/Domains/TeamDomain/Interface/Repository/TeamRepository.swift b/Projects/Domains/TeamDomain/Interface/Repository/TeamRepository.swift
index 9a9d3a697..24dc4472f 100644
--- a/Projects/Domains/TeamDomain/Interface/Repository/TeamRepository.swift
+++ b/Projects/Domains/TeamDomain/Interface/Repository/TeamRepository.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol TeamRepository {
+public protocol TeamRepository: Sendable {
func fetchTeamList() -> Single<[TeamListEntity]>
}
diff --git a/Projects/Domains/TeamDomain/Interface/UseCase/FetchTeamListUseCase.swift b/Projects/Domains/TeamDomain/Interface/UseCase/FetchTeamListUseCase.swift
index a5e5ab653..349099bea 100644
--- a/Projects/Domains/TeamDomain/Interface/UseCase/FetchTeamListUseCase.swift
+++ b/Projects/Domains/TeamDomain/Interface/UseCase/FetchTeamListUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchTeamListUseCase {
+public protocol FetchTeamListUseCase: Sendable {
func execute() -> Single<[TeamListEntity]>
}
diff --git a/Projects/Domains/TeamDomain/Sources/DataSource/RemoteTeamDataSourceImpl.swift b/Projects/Domains/TeamDomain/Sources/DataSource/RemoteTeamDataSourceImpl.swift
index 2b9c348f8..57a13932b 100644
--- a/Projects/Domains/TeamDomain/Sources/DataSource/RemoteTeamDataSourceImpl.swift
+++ b/Projects/Domains/TeamDomain/Sources/DataSource/RemoteTeamDataSourceImpl.swift
@@ -3,7 +3,7 @@ import Foundation
import RxSwift
import TeamDomainInterface
-public final class RemoteTeamDataSourceImpl: BaseRemoteDataSource, RemoteTeamDataSource {
+public final class RemoteTeamDataSourceImpl: BaseRemoteDataSource, RemoteTeamDataSource, @unchecked Sendable {
public func fetchTeamList() -> Single<[TeamListEntity]> {
request(.fetchTeamList)
.map([FetchTeamListResponseDTO].self)
diff --git a/Projects/Domains/UserDomain/Interface/DataSource/RemoteUserDataSource.swift b/Projects/Domains/UserDomain/Interface/DataSource/RemoteUserDataSource.swift
index 4ff9bdad9..d3a3849cf 100644
--- a/Projects/Domains/UserDomain/Interface/DataSource/RemoteUserDataSource.swift
+++ b/Projects/Domains/UserDomain/Interface/DataSource/RemoteUserDataSource.swift
@@ -2,7 +2,7 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol RemoteUserDataSource {
+public protocol RemoteUserDataSource: Sendable {
func setProfile(image: String) -> Completable
func setUserName(name: String) -> Completable
func fetchPlaylist() -> Single<[PlaylistEntity]>
diff --git a/Projects/Domains/UserDomain/Interface/Entity/FavoriteSongEntity.swift b/Projects/Domains/UserDomain/Interface/Entity/FavoriteSongEntity.swift
index f75e05fcb..e87d85bd5 100644
--- a/Projects/Domains/UserDomain/Interface/Entity/FavoriteSongEntity.swift
+++ b/Projects/Domains/UserDomain/Interface/Entity/FavoriteSongEntity.swift
@@ -1,7 +1,8 @@
import Foundation
import SongsDomainInterface
-public struct FavoriteSongEntity: Equatable {
+// TODO: concurrency๋ฅผ ์ํ Model์ Mutable ์ ๊ฑฐ ํ์
+public struct FavoriteSongEntity: Equatable, @unchecked Sendable {
public init(songID: String, title: String, artist: String, like: Int) {
self.songID = songID
self.title = title
diff --git a/Projects/Domains/UserDomain/Interface/Repository/UserRepository.swift b/Projects/Domains/UserDomain/Interface/Repository/UserRepository.swift
index 0a61d777f..75581a314 100644
--- a/Projects/Domains/UserDomain/Interface/Repository/UserRepository.swift
+++ b/Projects/Domains/UserDomain/Interface/Repository/UserRepository.swift
@@ -2,7 +2,7 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol UserRepository {
+public protocol UserRepository: Sendable {
func setProfile(image: String) -> Completable
func setUserName(name: String) -> Completable
func fetchPlaylist() -> Single<[PlaylistEntity]>
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/DeleteFavoriteListUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/DeleteFavoriteListUseCase.swift
index 0a20c0fc3..0c5659f70 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/DeleteFavoriteListUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/DeleteFavoriteListUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol DeleteFavoriteListUseCase {
+public protocol DeleteFavoriteListUseCase: Sendable {
func execute(ids: [String]) -> Completable
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/DeletePlaylistUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/DeletePlaylistUseCase.swift
index 47790162b..bbe5b24a4 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/DeletePlaylistUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/DeletePlaylistUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol DeletePlaylistUseCase {
+public protocol DeletePlaylistUseCase: Sendable {
func execute(ids: [String]) -> Completable
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/DrawFruitUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/DrawFruitUseCase.swift
index db3bae005..9bd75b371 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/DrawFruitUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/DrawFruitUseCase.swift
@@ -1,5 +1,5 @@
import RxSwift
-public protocol DrawFruitUseCase {
+public protocol DrawFruitUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/EditFavoriteSongsOrderUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/EditFavoriteSongsOrderUseCase.swift
index 7347aed7e..1451813ea 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/EditFavoriteSongsOrderUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/EditFavoriteSongsOrderUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol EditFavoriteSongsOrderUseCase {
+public protocol EditFavoriteSongsOrderUseCase: Sendable {
func execute(ids: [String]) -> Completable
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/EditPlaylistOrderUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/EditPlaylistOrderUseCase.swift
index dcca28bc3..d7f6c5263 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/EditPlaylistOrderUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/EditPlaylistOrderUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol EditPlaylistOrderUseCase {
+public protocol EditPlaylistOrderUseCase: Sendable {
func execute(ids: [String]) -> Completable
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/FetchFavoriteSongsUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/FetchFavoriteSongsUseCase.swift
index 4d872c3dd..ebad66746 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/FetchFavoriteSongsUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/FetchFavoriteSongsUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchFavoriteSongsUseCase {
+public protocol FetchFavoriteSongsUseCase: Sendable {
func execute() -> Single<[FavoriteSongEntity]>
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/FetchFruitDrawStatusUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/FetchFruitDrawStatusUseCase.swift
index 475d1c502..626bab570 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/FetchFruitDrawStatusUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/FetchFruitDrawStatusUseCase.swift
@@ -1,5 +1,5 @@
import RxSwift
-public protocol FetchFruitDrawStatusUseCase {
+public protocol FetchFruitDrawStatusUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/FetchFruitListUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/FetchFruitListUseCase.swift
index 5d5db31d6..3302bd0b1 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/FetchFruitListUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/FetchFruitListUseCase.swift
@@ -1,5 +1,5 @@
import RxSwift
-public protocol FetchFruitListUseCase {
+public protocol FetchFruitListUseCase: Sendable {
func execute() -> Single<[FruitEntity]>
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/FetchPlaylistUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/FetchPlaylistUseCase.swift
index 893de9add..ff36e4697 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/FetchPlaylistUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/FetchPlaylistUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchPlaylistUseCase {
+public protocol FetchPlaylistUseCase: Sendable {
func execute() -> Single<[PlaylistEntity]>
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/FetchUserInfoUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/FetchUserInfoUseCase.swift
index 68311c55c..6d4214358 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/FetchUserInfoUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/FetchUserInfoUseCase.swift
@@ -1,6 +1,6 @@
import Foundation
import RxSwift
-public protocol FetchUserInfoUseCase {
+public protocol FetchUserInfoUseCase: Sendable {
func execute() -> Single
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/SetProfileUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/SetProfileUseCase.swift
index 484b410c7..d1a650d8a 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/SetProfileUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/SetProfileUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol SetProfileUseCase {
+public protocol SetProfileUseCase: Sendable {
func execute(image: String) -> Completable
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/SetUserNameUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/SetUserNameUseCase.swift
index 10e04d8aa..0085c9e01 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/SetUserNameUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/SetUserNameUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol SetUserNameUseCase {
+public protocol SetUserNameUseCase: Sendable {
func execute(name: String) -> Completable
}
diff --git a/Projects/Domains/UserDomain/Interface/UseCase/WithdrawUserInfoUseCase.swift b/Projects/Domains/UserDomain/Interface/UseCase/WithdrawUserInfoUseCase.swift
index 5ed6ce676..8b7d11768 100644
--- a/Projects/Domains/UserDomain/Interface/UseCase/WithdrawUserInfoUseCase.swift
+++ b/Projects/Domains/UserDomain/Interface/UseCase/WithdrawUserInfoUseCase.swift
@@ -2,6 +2,6 @@ import BaseDomainInterface
import Foundation
import RxSwift
-public protocol WithdrawUserInfoUseCase {
+public protocol WithdrawUserInfoUseCase: Sendable {
func execute() -> Completable
}
diff --git a/Projects/Domains/UserDomain/Testing/FetchFavoriteSongsUseCaseStub.swift b/Projects/Domains/UserDomain/Testing/FetchFavoriteSongsUseCaseStub.swift
index f37a39c63..c8219c03a 100644
--- a/Projects/Domains/UserDomain/Testing/FetchFavoriteSongsUseCaseStub.swift
+++ b/Projects/Domains/UserDomain/Testing/FetchFavoriteSongsUseCaseStub.swift
@@ -2,7 +2,7 @@ import Foundation
import RxSwift
import UserDomainInterface
-public struct FetchFavoriteSongsUseCaseStub: FetchFavoriteSongsUseCase {
+public struct FetchFavoriteSongsUseCaseStub: FetchFavoriteSongsUseCase, @unchecked Sendable {
let items: [FavoriteSongEntity] = [
.init(
songID: "fgSXAKsq-Vo",
diff --git a/Projects/Domains/UserDomain/Testing/FetchPlaylistUseCaseStub.swift b/Projects/Domains/UserDomain/Testing/FetchPlaylistUseCaseStub.swift
index eb31b2137..e1dfe3a2c 100644
--- a/Projects/Domains/UserDomain/Testing/FetchPlaylistUseCaseStub.swift
+++ b/Projects/Domains/UserDomain/Testing/FetchPlaylistUseCaseStub.swift
@@ -2,7 +2,7 @@ import Foundation
import RxSwift
import UserDomainInterface
-public struct FetchPlaylistUseCaseStub: FetchPlaylistUseCase {
+public struct FetchPlaylistUseCaseStub: FetchPlaylistUseCase, @unchecked Sendable {
let items: [PlaylistEntity] = [
.init(
key: "123",
diff --git a/Projects/Features/ArtistFeature/Interface/ArtistDetailFactory.swift b/Projects/Features/ArtistFeature/Interface/ArtistDetailFactory.swift
index 21751cdc3..5b9a7da11 100644
--- a/Projects/Features/ArtistFeature/Interface/ArtistDetailFactory.swift
+++ b/Projects/Features/ArtistFeature/Interface/ArtistDetailFactory.swift
@@ -2,6 +2,7 @@ import ArtistDomainInterface
import Foundation
import UIKit
+@MainActor
public protocol ArtistDetailFactory {
func makeView(artistID: String) -> UIViewController
}
diff --git a/Projects/Features/ArtistFeature/Interface/ArtistFactory.swift b/Projects/Features/ArtistFeature/Interface/ArtistFactory.swift
index b7e455886..8c1b1a6aa 100644
--- a/Projects/Features/ArtistFeature/Interface/ArtistFactory.swift
+++ b/Projects/Features/ArtistFeature/Interface/ArtistFactory.swift
@@ -1,6 +1,7 @@
import Foundation
import UIKit
+@MainActor
public protocol ArtistFactory {
func makeView() -> UIViewController
}
diff --git a/Projects/Features/ArtistFeature/Sources/Components/ArtistMusicComponent.swift b/Projects/Features/ArtistFeature/Sources/Components/ArtistMusicComponent.swift
index b3251233f..c6743ac84 100644
--- a/Projects/Features/ArtistFeature/Sources/Components/ArtistMusicComponent.swift
+++ b/Projects/Features/ArtistFeature/Sources/Components/ArtistMusicComponent.swift
@@ -14,6 +14,7 @@ public protocol ArtistMusicDependency: Dependency {
var artistMusicContentComponent: ArtistMusicContentComponent { get }
}
+@MainActor
public final class ArtistMusicComponent: Component {
public func makeView(model: ArtistEntity?) -> ArtistMusicViewController {
return ArtistMusicViewController.viewController(
diff --git a/Projects/Features/ArtistFeature/Sources/Components/ArtistMusicContentComponent.swift b/Projects/Features/ArtistFeature/Sources/Components/ArtistMusicContentComponent.swift
index 95846a0ab..03293d923 100644
--- a/Projects/Features/ArtistFeature/Sources/Components/ArtistMusicContentComponent.swift
+++ b/Projects/Features/ArtistFeature/Sources/Components/ArtistMusicContentComponent.swift
@@ -13,6 +13,7 @@ public protocol ArtistMusicContentDependency: Dependency {
var songDetailPresenter: any SongDetailPresentable { get }
}
+@MainActor
public final class ArtistMusicContentComponent: Component {
public func makeView(
type: ArtistSongSortType,
diff --git a/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistDetailViewController.swift b/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistDetailViewController.swift
index 1a0baaac7..eb91e232f 100644
--- a/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistDetailViewController.swift
+++ b/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistDetailViewController.swift
@@ -9,7 +9,8 @@ import SignInFeatureInterface
import UIKit
import Utility
-public final class ArtistDetailViewController: UIViewController, ViewControllerFromStoryBoard, ContainerViewType {
+public final class ArtistDetailViewController: UIViewController, ViewControllerFromStoryBoard,
+ @preconcurrency ContainerViewType {
@IBOutlet weak var gradationView: UIView!
@IBOutlet weak var backButton: UIButton!
@IBOutlet weak var subscriptionButton: UIButton!
diff --git a/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistMusicContentViewController.swift b/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistMusicContentViewController.swift
index f3d57ef88..f94bc6b3f 100644
--- a/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistMusicContentViewController.swift
+++ b/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistMusicContentViewController.swift
@@ -13,7 +13,7 @@ import UIKit
import Utility
public final class ArtistMusicContentViewController:
- BaseViewController, ViewControllerFromStoryBoard, SongCartViewType {
+ BaseViewController, ViewControllerFromStoryBoard, @preconcurrency SongCartViewType {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var activityIndidator: NVActivityIndicatorView!
@IBOutlet weak var songCartOnView: UIView!
@@ -238,7 +238,7 @@ extension ArtistMusicContentViewController: SongCartViewDelegate {
let log = CommonAnalyticsLog.clickAddMusicsButton(location: .artist)
LogManager.analytics(log)
- if PreferenceManager.userInfo == nil {
+ if PreferenceManager.shared.userInfo == nil {
output.showLogin.onNext(.addMusics)
return
}
@@ -341,14 +341,18 @@ extension ArtistMusicContentViewController: PlayButtonGroupViewDelegate {
extension Reactive where Base: ArtistMusicContentViewController {
var refresh: Binder {
return Binder(base) { viewController, _ in
- viewController.input.pageID.accept(1)
+ Task { @MainActor in
+ viewController.input.pageID.accept(1)
+ }
}
}
var loadMore: Binder {
return Binder(base) { viewController, _ in
- let pageID = viewController.input.pageID.value
- viewController.input.pageID.accept(pageID + 1)
+ Task { @MainActor in
+ let pageID = viewController.input.pageID.value
+ viewController.input.pageID.accept(pageID + 1)
+ }
}
}
}
diff --git a/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistMusicViewController.swift b/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistMusicViewController.swift
index 207a94b27..1a9e3dc40 100644
--- a/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistMusicViewController.swift
+++ b/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistMusicViewController.swift
@@ -87,7 +87,7 @@ extension ArtistMusicViewController {
}
}
-extension ArtistMusicViewController: PageboyViewControllerDataSource, TMBarDataSource {
+extension ArtistMusicViewController: @preconcurrency PageboyViewControllerDataSource, @preconcurrency TMBarDataSource {
public func barItem(for bar: TMBar, at index: Int) -> TMBarItemable {
switch index {
case 0:
diff --git a/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistViewController.swift b/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistViewController.swift
index 45948439e..b570081b1 100644
--- a/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistViewController.swift
+++ b/Projects/Features/ArtistFeature/Sources/ViewControllers/ArtistViewController.swift
@@ -15,7 +15,7 @@ public final class ArtistViewController:
BaseViewController,
ViewControllerFromStoryBoard,
EqualHandleTappedType,
- StoryboardView {
+ @preconcurrency StoryboardView {
public typealias Reactor = ArtistReactor
@IBOutlet weak var collectionView: UICollectionView!
@@ -201,13 +201,15 @@ extension ArtistViewController: WaterfallLayoutDelegate {
}
public extension ArtistViewController {
- func equalHandleTapped() {
- let viewControllersCount: Int = self.navigationController?.viewControllers.count ?? 0
- if viewControllersCount > 1 {
- self.navigationController?.popToRootViewController(animated: true)
- } else {
- guard reactor?.currentState.artistList.isEmpty == false else { return }
- self.collectionView.setContentOffset(CGPoint(x: 0, y: -STATUS_BAR_HEGHIT()), animated: true)
+ nonisolated func equalHandleTapped() {
+ Task { @MainActor in
+ let viewControllersCount: Int = self.navigationController?.viewControllers.count ?? 0
+ if viewControllersCount > 1 {
+ self.navigationController?.popToRootViewController(animated: true)
+ } else {
+ guard reactor?.currentState.artistList.isEmpty == false else { return }
+ self.collectionView.setContentOffset(CGPoint(x: 0, y: -STATUS_BAR_HEGHIT()), animated: true)
+ }
}
}
}
diff --git a/Projects/Features/ArtistFeature/Sources/ViewModels/ArtistDetailViewModel.swift b/Projects/Features/ArtistFeature/Sources/ViewModels/ArtistDetailViewModel.swift
index 391eeac53..02d2b5661 100644
--- a/Projects/Features/ArtistFeature/Sources/ViewModels/ArtistDetailViewModel.swift
+++ b/Projects/Features/ArtistFeature/Sources/ViewModels/ArtistDetailViewModel.swift
@@ -59,8 +59,8 @@ public final class ArtistDetailViewModel: ViewModelType {
.disposed(by: disposeBag)
input.fetchArtistSubscriptionStatus
- .withLatestFrom(PreferenceManager.$userInfo)
- .withLatestFrom(PreferenceManager.$pushNotificationAuthorizationStatus) { ($0, $1 ?? false) }
+ .withLatestFrom(PreferenceManager.shared.$userInfo)
+ .withLatestFrom(PreferenceManager.shared.$pushNotificationAuthorizationStatus) { ($0, $1 ?? false) }
.flatMap { [fetchArtistSubscriptionStatusUseCase] userInfo, granted
-> Observable in
if userInfo == nil || granted == false {
@@ -81,7 +81,7 @@ public final class ArtistDetailViewModel: ViewModelType {
ArtistAnalyticsLog.clickArtistSubscriptionButton(artist: id)
)
})
- .withLatestFrom(PreferenceManager.$userInfo)
+ .withLatestFrom(PreferenceManager.shared.$userInfo)
.filter { userInfo in
if userInfo == nil {
output.showLogin.onNext(.artistSubscribe)
@@ -89,7 +89,7 @@ public final class ArtistDetailViewModel: ViewModelType {
}
return true
}
- .withLatestFrom(PreferenceManager.$pushNotificationAuthorizationStatus)
+ .withLatestFrom(PreferenceManager.shared.$pushNotificationAuthorizationStatus)
.map { $0 ?? false }
.filter { granted in
if granted == false {
@@ -118,8 +118,8 @@ public final class ArtistDetailViewModel: ViewModelType {
// ๋ก๊ทธ์ธ/์์, ๊ธฐ๊ธฐ์๋ฆผ ๋ ์ํ ๋ฐ์
Observable.combineLatest(
- PreferenceManager.$userInfo.map { $0?.ID }.distinctUntilChanged(),
- PreferenceManager.$pushNotificationAuthorizationStatus.distinctUntilChanged().map { $0 ?? false }
+ PreferenceManager.shared.$userInfo.map { $0?.ID }.distinctUntilChanged(),
+ PreferenceManager.shared.$pushNotificationAuthorizationStatus.distinctUntilChanged().map { $0 ?? false }
) { id, granted -> (String?, Bool) in
return (id, granted)
}
diff --git a/Projects/Features/ArtistFeature/Sources/ViewModels/ArtistMusicContentViewModel.swift b/Projects/Features/ArtistFeature/Sources/ViewModels/ArtistMusicContentViewModel.swift
index bbf1f42b2..2a8a32067 100644
--- a/Projects/Features/ArtistFeature/Sources/ViewModels/ArtistMusicContentViewModel.swift
+++ b/Projects/Features/ArtistFeature/Sources/ViewModels/ArtistMusicContentViewModel.swift
@@ -102,7 +102,7 @@ public final class ArtistMusicContentViewModel: ViewModelType {
.bind(to: output.indexOfSelectedSongs)
.disposed(by: disposeBag)
- Utility.PreferenceManager.$startPage
+ Utility.PreferenceManager.shared.$startPage
.skip(1)
.map { _ in [] }
.bind(to: output.indexOfSelectedSongs)
diff --git a/Projects/Features/ArtistFeature/Sources/Views/ArtistMusicCell.swift b/Projects/Features/ArtistFeature/Sources/Views/ArtistMusicCell.swift
index 211ff81e3..acbe9db71 100644
--- a/Projects/Features/ArtistFeature/Sources/Views/ArtistMusicCell.swift
+++ b/Projects/Features/ArtistFeature/Sources/Views/ArtistMusicCell.swift
@@ -6,6 +6,7 @@ import SongsDomainInterface
import UIKit
import Utility
+@MainActor
protocol ArtistMusicCellDelegate: AnyObject {
func tappedThumbnail(id: String)
}
@@ -22,16 +23,18 @@ final class ArtistMusicCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- backgroundColor = .clear
- contentView.backgroundColor = .clear
+ Task { @MainActor in
+ backgroundColor = .clear
+ contentView.backgroundColor = .clear
- albumImageButton.layer.cornerRadius = 4
- albumImageButton.contentMode = .scaleAspectFill
- albumImageButton.clipsToBounds = true
+ albumImageButton.layer.cornerRadius = 4
+ albumImageButton.contentMode = .scaleAspectFill
+ albumImageButton.clipsToBounds = true
- titleStringLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 14)
- groupStringLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
- releaseDateLabel.font = DesignSystemFontFamily.SCoreDream._3Light.font(size: 12)
+ titleStringLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 14)
+ groupStringLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
+ releaseDateLabel.font = DesignSystemFontFamily.SCoreDream._3Light.font(size: 12)
+ }
}
@IBAction func thumbnailToPlayButtonAction(_ sender: Any) {
diff --git a/Projects/Features/ArtistFeature/Sources/WaterfallLayout/WaterfallLayout.swift b/Projects/Features/ArtistFeature/Sources/WaterfallLayout/WaterfallLayout.swift
index a0d6439bc..e02d900b8 100644
--- a/Projects/Features/ArtistFeature/Sources/WaterfallLayout/WaterfallLayout.swift
+++ b/Projects/Features/ArtistFeature/Sources/WaterfallLayout/WaterfallLayout.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol WaterfallLayoutDelegate: AnyObject {
// MARK: - Required
func collectionViewLayout(for section: Int) -> WaterfallLayout.Layout
diff --git a/Projects/Features/BaseFeature/Interface/ContainSongs/ContainSongsFactory.swift b/Projects/Features/BaseFeature/Interface/ContainSongs/ContainSongsFactory.swift
index 930bfb13c..ed34086eb 100644
--- a/Projects/Features/BaseFeature/Interface/ContainSongs/ContainSongsFactory.swift
+++ b/Projects/Features/BaseFeature/Interface/ContainSongs/ContainSongsFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol ContainSongsFactory {
func makeView(songs: [String]) -> UIViewController
}
diff --git a/Projects/Features/BaseFeature/Interface/MultiPurposePopup/MultiPurposePopupFactory.swift b/Projects/Features/BaseFeature/Interface/MultiPurposePopup/MultiPurposePopupFactory.swift
index bce2c594a..21857f08d 100644
--- a/Projects/Features/BaseFeature/Interface/MultiPurposePopup/MultiPurposePopupFactory.swift
+++ b/Projects/Features/BaseFeature/Interface/MultiPurposePopup/MultiPurposePopupFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol MultiPurposePopupFactory {
func makeView(
type: PurposeType,
diff --git a/Projects/Features/BaseFeature/Interface/Privacy/PrivacyFactory.swift b/Projects/Features/BaseFeature/Interface/Privacy/PrivacyFactory.swift
index 75be26c6c..65113fb0d 100644
--- a/Projects/Features/BaseFeature/Interface/Privacy/PrivacyFactory.swift
+++ b/Projects/Features/BaseFeature/Interface/Privacy/PrivacyFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol PrivacyFactory {
func makeView() -> UIViewController
}
diff --git a/Projects/Features/BaseFeature/Interface/ServiceTerm/ServiceTermFactory.swift b/Projects/Features/BaseFeature/Interface/ServiceTerm/ServiceTermFactory.swift
index da3a20d2e..333e67ccb 100644
--- a/Projects/Features/BaseFeature/Interface/ServiceTerm/ServiceTermFactory.swift
+++ b/Projects/Features/BaseFeature/Interface/ServiceTerm/ServiceTermFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol ServiceTermFactory {
func makeView() -> UIViewController
}
diff --git a/Projects/Features/BaseFeature/Interface/TextPopup/TextPopupFactory.swift b/Projects/Features/BaseFeature/Interface/TextPopup/TextPopupFactory.swift
index e4abc1518..ce4078bc1 100644
--- a/Projects/Features/BaseFeature/Interface/TextPopup/TextPopupFactory.swift
+++ b/Projects/Features/BaseFeature/Interface/TextPopup/TextPopupFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol TextPopupFactory {
func makeView(
text: String?,
diff --git a/Projects/Features/BaseFeature/Sources/Etc/PlayState/PlayState+Playlist.swift b/Projects/Features/BaseFeature/Sources/Etc/PlayState/PlayState+Playlist.swift
index 1bef4fcf0..99dbe58b0 100644
--- a/Projects/Features/BaseFeature/Sources/Etc/PlayState/PlayState+Playlist.swift
+++ b/Projects/Features/BaseFeature/Sources/Etc/PlayState/PlayState+Playlist.swift
@@ -11,7 +11,8 @@ import Foundation
import SongsDomainInterface
import Utility
-final class Playlist {
+final class Playlist: @unchecked Sendable {
+ private let lock = NSRecursiveLock()
@Published private(set) var list: [PlaylistItem] = []
init(list: [PlaylistItem] = []) {
@@ -26,27 +27,39 @@ final class Playlist {
}
func append(_ item: PlaylistItem) {
- list.append(item)
+ lock.withLock {
+ list.append(item)
+ }
}
func append(_ items: [PlaylistItem]) {
- list.append(contentsOf: items)
+ lock.withLock {
+ list.append(contentsOf: items)
+ }
}
func insert(_ newElement: PlaylistItem, at: Int) {
- list.insert(newElement, at: at)
+ lock.withLock {
+ list.insert(newElement, at: at)
+ }
}
func update(contentsOf items: [PlaylistItem]) {
- list = items
+ lock.withLock {
+ list = items
+ }
}
func remove(at index: Int) {
+ lock.lock()
+ defer { lock.unlock() }
guard list[safe: index] != nil else { return }
list.remove(at: index)
}
func remove(indexs: [Int]) {
+ lock.lock()
+ defer { lock.unlock() }
let sortedIndexs = indexs.sorted(by: >) // ์์์๋ถํฐ ์ญ์ ํ๋ฉด ์ธ๋ฑ์ค ์์๊ฐ ๋ฐ๋
sortedIndexs.forEach { index in
remove(at: index)
@@ -54,28 +67,40 @@ final class Playlist {
}
func remove(id: String) {
+ lock.lock()
+ defer { lock.unlock() }
if let index = list.firstIndex(where: { $0.id == id }) {
remove(at: index)
}
}
func removeAll() {
- list.removeAll()
+ lock.withLock {
+ list.removeAll()
+ }
}
func removeAll(where shouldBeRemoved: (PlaylistItem) -> Bool) {
- list.removeAll(where: shouldBeRemoved)
+ lock.withLock {
+ list.removeAll(where: shouldBeRemoved)
+ }
}
func contains(_ item: PlaylistItem) -> Bool {
- return list.contains(item)
+ return lock.withLock {
+ list.contains(item)
+ }
}
func contains(id: String) -> Bool {
- return list.contains { $0.id == id }
+ return lock.withLock {
+ list.contains { $0.id == id }
+ }
}
func reorderPlaylist(from: Int, to: Int) {
+ lock.lock()
+ defer { lock.unlock() }
let movedData = list[from]
list.remove(at: from)
list.insert(movedData, at: to)
@@ -83,6 +108,8 @@ final class Playlist {
/// ํด๋น ๊ณก์ด ์ด๋ฏธ ์ฌ์๋ชฉ๋ก์ ์์ผ๋ฉด ์ฌ์๋ชฉ๋ก ์ ํด๋น ๊ณก์ index, ์์ผ๋ฉด nil ๋ฆฌํด
func uniqueIndex(of item: PlaylistItem) -> Int? {
- return list.firstIndex(of: item)
+ return lock.withLock {
+ list.firstIndex(of: item)
+ }
}
}
diff --git a/Projects/Features/BaseFeature/Sources/Etc/PlayState/PlayState.swift b/Projects/Features/BaseFeature/Sources/Etc/PlayState/PlayState.swift
index 7a844c459..bc7a1c461 100644
--- a/Projects/Features/BaseFeature/Sources/Etc/PlayState/PlayState.swift
+++ b/Projects/Features/BaseFeature/Sources/Etc/PlayState/PlayState.swift
@@ -13,9 +13,9 @@ import SongsDomainInterface
import Utility
/// ์์ ํ ๋๋ฉ์ธ ๋ก์ง์ผ๋ก ์ ํ ๊ณ ๋ ค
-public final class PlayState {
+public final class PlayState: @unchecked Sendable {
public static let shared = PlayState()
- private var playlist: Playlist
+ private let playlist: Playlist
private var subscription = Set()
public var count: Int { playlist.count }
public var isEmpty: Bool { playlist.isEmpty }
diff --git a/Projects/Features/BaseFeature/Sources/Protocols/EditSheetViewType.swift b/Projects/Features/BaseFeature/Sources/Protocols/EditSheetViewType.swift
index 66f680f61..1039a9785 100644
--- a/Projects/Features/BaseFeature/Sources/Protocols/EditSheetViewType.swift
+++ b/Projects/Features/BaseFeature/Sources/Protocols/EditSheetViewType.swift
@@ -11,6 +11,7 @@ import Foundation
import UIKit
import Utility
+/// ๊ฐ์ mutable ํ์
ํด๊ฒฐํด์ผํจ... @preconcurrency
public protocol EditSheetViewType: AnyObject {
var editSheetView: EditSheetView! { get set }
var bottomSheetView: BottomSheetView! { get set }
@@ -21,6 +22,7 @@ public enum EditSheetType {
case profile // ๋ณด๊ดํจ > ํ๋กํ ํธ์ง
}
+@MainActor
public extension EditSheetViewType where Self: UIViewController {
/// ํธ์งํ๊ธฐ ํ์
์ ๋์๋๋ค.
/// - Parameter view: ํ์
์ ๋ถ์ผ ๋์์ด ๋๋ ๋ทฐ (ex: ์ํฐ์คํธ ๋
ธ๋ ๋ฆฌ์คํธ, viewController.view)
diff --git a/Projects/Features/BaseFeature/Sources/Protocols/PlaylistEditSheetViewType.swift b/Projects/Features/BaseFeature/Sources/Protocols/PlaylistEditSheetViewType.swift
index 0e1366615..378160fa6 100644
--- a/Projects/Features/BaseFeature/Sources/Protocols/PlaylistEditSheetViewType.swift
+++ b/Projects/Features/BaseFeature/Sources/Protocols/PlaylistEditSheetViewType.swift
@@ -3,6 +3,7 @@ import Foundation
import UIKit
import Utility
+/// concurrency๋ฅผ ์ํด mutable ์ํ ๋ฆฌํฉํ ๋ง ํ์
public protocol PlaylistEditSheetViewType: AnyObject {
var playlisteditSheetView: PlaylistEditSheetView! { get set }
var bottomSheetView: BottomSheetView! { get set }
@@ -13,6 +14,7 @@ public enum PlaylistEditType {
case share
}
+@MainActor
public extension PlaylistEditSheetViewType where Self: UIViewController {
/// ํธ์งํ๊ธฐ ํ์
์ ๋์๋๋ค.
/// - Parameter view: ํ์
์ ๋ถ์ผ ๋์์ด ๋๋ ๋ทฐ (ex: ์ํฐ์คํธ ๋
ธ๋ ๋ฆฌ์คํธ, viewController.view)
diff --git a/Projects/Features/BaseFeature/Sources/Protocols/SongCartViewType.swift b/Projects/Features/BaseFeature/Sources/Protocols/SongCartViewType.swift
index 1a696743d..f76b25bec 100644
--- a/Projects/Features/BaseFeature/Sources/Protocols/SongCartViewType.swift
+++ b/Projects/Features/BaseFeature/Sources/Protocols/SongCartViewType.swift
@@ -11,6 +11,7 @@ import Foundation
import UIKit
import Utility
+/// SongCartViewType ์ด๋ป๊ฒ๋ ํด๊ฒฐํด์ผํจ..
public protocol SongCartViewType: AnyObject {
var songCartView: SongCartView! { get set }
var bottomSheetView: BottomSheetView! { get set }
@@ -29,6 +30,7 @@ public enum SongCartType {
case creditSong // ํฌ๋ ๋ง ์์
์ ๋
ธ๋ ๋ฆฌ์คํธ (๋ฐฑํผ)
}
+@MainActor
public extension SongCartViewType where Self: UIViewController {
/// ๋
ธ๋ ๋ด๊ธฐ ํ์
์ ๋์๋๋ค.
/// - Parameter view: ํ์
์ ๋ถ์ผ ๋์์ด ๋๋ ๋ทฐ (ex: ์ํฐ์คํธ ๋
ธ๋ ๋ฆฌ์คํธ, viewController.view)
diff --git a/Projects/Features/BaseFeature/Sources/Protocols/WMBottomSheetViewType.swift b/Projects/Features/BaseFeature/Sources/Protocols/WMBottomSheetViewType.swift
index 2f01b0108..fe0df015f 100644
--- a/Projects/Features/BaseFeature/Sources/Protocols/WMBottomSheetViewType.swift
+++ b/Projects/Features/BaseFeature/Sources/Protocols/WMBottomSheetViewType.swift
@@ -7,6 +7,7 @@ public protocol WMBottomSheetViewType: AnyObject {
var bottomSheetView: BottomSheetView! { get set }
}
+@MainActor
public extension WMBottomSheetViewType where Self: UIViewController {
/// ํธ์งํ๊ธฐ ํ์
์ ๋์๋๋ค.
/// - Parameter view: ํ์
์ ๋ถ์ผ ๋์์ด ๋๋ ๋ทฐ
diff --git a/Projects/Features/BaseFeature/Sources/ViewControllers/BaseReactorViewController.swift b/Projects/Features/BaseFeature/Sources/ViewControllers/BaseReactorViewController.swift
index 399f0bcab..e206c885f 100644
--- a/Projects/Features/BaseFeature/Sources/ViewControllers/BaseReactorViewController.swift
+++ b/Projects/Features/BaseFeature/Sources/ViewControllers/BaseReactorViewController.swift
@@ -6,7 +6,7 @@ import SnapKit
import Then
import UIKit
-open class BaseReactorViewController: UIViewController, View {
+open class BaseReactorViewController: UIViewController, @preconcurrency View {
public var disposeBag = DisposeBag()
open lazy var indicator = NVActivityIndicatorView(frame: .zero).then {
$0.color = DesignSystemAsset.PrimaryColorV2.point.color
diff --git a/Projects/Features/BaseFeature/Sources/ViewControllers/BaseStoryboardReactorViewController.swift b/Projects/Features/BaseFeature/Sources/ViewControllers/BaseStoryboardReactorViewController.swift
index e51a38fa3..56be991c4 100644
--- a/Projects/Features/BaseFeature/Sources/ViewControllers/BaseStoryboardReactorViewController.swift
+++ b/Projects/Features/BaseFeature/Sources/ViewControllers/BaseStoryboardReactorViewController.swift
@@ -6,7 +6,8 @@ import Then
import UIKit
import Utility
-open class BaseStoryboardReactorViewController: UIViewController, StoryboardView,
+open class BaseStoryboardReactorViewController: UIViewController,
+ @preconcurrency StoryboardView,
ViewControllerFromStoryBoard {
public var disposeBag = DisposeBag()
diff --git a/Projects/Features/BaseFeature/Sources/ViewControllers/ContainSongsViewController.swift b/Projects/Features/BaseFeature/Sources/ViewControllers/ContainSongsViewController.swift
index 444f559b3..688d53537 100644
--- a/Projects/Features/BaseFeature/Sources/ViewControllers/ContainSongsViewController.swift
+++ b/Projects/Features/BaseFeature/Sources/ViewControllers/ContainSongsViewController.swift
@@ -153,7 +153,7 @@ extension ContainSongsViewController {
.disposed(by: disposeBag)
output.showPricePopup
- .withLatestFrom(PreferenceManager.$userInfo) { $1 }
+ .withLatestFrom(PreferenceManager.shared.$userInfo) { $1 }
.compactMap { $0 }
.withLatestFrom(output.creationPrice) { ($0, $1) }
.bind(with: self) { owner, info in
diff --git a/Projects/Features/BaseFeature/Sources/ViewControllers/ContractViewController.swift b/Projects/Features/BaseFeature/Sources/ViewControllers/ContractViewController.swift
index 0e8fe94d8..6b6070014 100644
--- a/Projects/Features/BaseFeature/Sources/ViewControllers/ContractViewController.swift
+++ b/Projects/Features/BaseFeature/Sources/ViewControllers/ContractViewController.swift
@@ -16,7 +16,7 @@ import SnapKit
import UIKit
import Utility
-public enum ContractType {
+public enum ContractType: Sendable {
case privacy
case service
}
@@ -111,13 +111,17 @@ private extension ContractViewController {
private extension ContractViewController {
func loadPDF() {
- DispatchQueue.global(qos: .default).async {
- guard let url = URL(string: self.type.url),
+ DispatchQueue.global(qos: .default).async { [type] in
+ guard let url = URL(string: type.url),
let document = PDFDocument(url: url) else {
- self.loadFailPDF()
+ Task { @MainActor in
+ self.loadFailPDF()
+ }
return
}
- self.configurePDF(document: document)
+ Task { @MainActor in
+ self.configurePDF(document: document)
+ }
}
}
diff --git a/Projects/Features/BaseFeature/Sources/ViewModels/ContainSongsViewModel.swift b/Projects/Features/BaseFeature/Sources/ViewModels/ContainSongsViewModel.swift
index e8f8ca33e..34972d57a 100644
--- a/Projects/Features/BaseFeature/Sources/ViewModels/ContainSongsViewModel.swift
+++ b/Projects/Features/BaseFeature/Sources/ViewModels/ContainSongsViewModel.swift
@@ -104,7 +104,7 @@ public final class ContainSongsViewModel: ViewModelType {
))
})
.catchAndReturn([])
- .withLatestFrom(PreferenceManager.$userInfo) { ($0, $1) }
+ .withLatestFrom(PreferenceManager.shared.$userInfo) { ($0, $1) }
.map { playlist, userInfo in
return playlist.filter { $0.userId == userInfo?.decryptedID }
diff --git a/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetCalculator.swift b/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetCalculator.swift
index f0a5d1886..2a346b067 100644
--- a/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetCalculator.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetCalculator.swift
@@ -6,6 +6,7 @@ import UIKit
import Utility
extension CGFloat {
+ @MainActor
static var safeAreaBottomInset: CGFloat {
return SAFEAREA_BOTTOM_HEIGHT()
}
@@ -18,6 +19,7 @@ enum BottomSheetCalculator {
/// - contentView: the content view of the bottom sheet
/// - superview: the bottom sheet container view
/// - height: preferred height for the content view
+ @MainActor
static func offset(
for contentView: UIView,
in superview: UIView,
@@ -34,6 +36,7 @@ enum BottomSheetCalculator {
return max(superview.frame.height - targetHeight, 0)
}
+ @MainActor
static func contentHeight(
for contentView: UIView,
in superview: UIView,
@@ -59,6 +62,7 @@ enum BottomSheetCalculator {
/// - currentTargetIndex: index of the current target offset of the BottomSheetView
/// - superview: the bottom sheet container view
/// - targetMaxHeight: flag specifying whether the last translation target should dismiss the BottomSheetView
+ @MainActor
static func createTranslationTargets(
for targetOffsets: [CGFloat],
at currentTargetIndex: Int,
diff --git a/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetPresentationController.swift b/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetPresentationController.swift
index 1036612ec..0b13fe6da 100644
--- a/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetPresentationController.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetPresentationController.swift
@@ -218,7 +218,7 @@ extension BottomSheetPresentationController: UIViewControllerInteractiveTransiti
// MARK: - BottomSheetViewPresenterDelegate
-extension BottomSheetPresentationController: BottomSheetViewDismissalDelegate {
+extension BottomSheetPresentationController: @preconcurrency BottomSheetViewDismissalDelegate {
func bottomSheetView(_ view: BottomSheetView, willDismissBy action: BottomSheetView.DismissAction) {
guard presentationDelegate?.bottomSheetPresentationController(self, shouldDismissBy: action) ?? true else {
view.reset()
diff --git a/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetTransitioningDelegate.swift b/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetTransitioningDelegate.swift
index a1f3dcb5f..a9c0b11e1 100644
--- a/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetTransitioningDelegate.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetTransitioningDelegate.swift
@@ -4,6 +4,7 @@
import UIKit
+@MainActor
public final class BottomSheetTransitioningDelegate: NSObject {
public private(set) var contentHeights: [CGFloat]
private var startTargetIndex: Int
diff --git a/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetView.swift b/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetView.swift
index dcff08090..9c884378f 100644
--- a/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetView.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/BottomSheet/BottomSheetView.swift
@@ -17,6 +17,7 @@ public extension CGFloat {
}
public extension Array where Element == CGFloat {
+ @MainActor
static var bottomSheetDefault: [CGFloat] {
let screenSize = UIScreen.main.bounds.size
@@ -44,7 +45,8 @@ public protocol BottomSheetViewAnimationDelegate: AnyObject {
// MARK: - View
public final class BottomSheetView: UIView {
- public enum HandleBackground {
+ @MainActor
+ public enum HandleBackground: Sendable {
case color(UIColor)
case visualEffect(UIVisualEffect)
diff --git a/Projects/Features/BaseFeature/Sources/Views/BottomSheet/SpringAnimator.swift b/Projects/Features/BaseFeature/Sources/Views/BottomSheet/SpringAnimator.swift
index 5df679f48..1b5a50aec 100644
--- a/Projects/Features/BaseFeature/Sources/Views/BottomSheet/SpringAnimator.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/BottomSheet/SpringAnimator.swift
@@ -10,6 +10,7 @@ extension SpringAnimator {
}
}
+@MainActor
class SpringAnimator: NSObject {
var fromPosition: CGPoint = .zero {
didSet {
diff --git a/Projects/Features/BaseFeature/Sources/Views/ContainPlaylistHeaderView.swift b/Projects/Features/BaseFeature/Sources/Views/ContainPlaylistHeaderView.swift
index 6af835b79..3a40098a1 100644
--- a/Projects/Features/BaseFeature/Sources/Views/ContainPlaylistHeaderView.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/ContainPlaylistHeaderView.swift
@@ -1,6 +1,7 @@
import DesignSystem
import UIKit
+@MainActor
public protocol ContainPlaylistHeaderViewDelegate: AnyObject {
func action()
}
diff --git a/Projects/Features/BaseFeature/Sources/Views/CurrentPlaylistTableViewCell.swift b/Projects/Features/BaseFeature/Sources/Views/CurrentPlaylistTableViewCell.swift
index ed104346f..3db6e4cd9 100644
--- a/Projects/Features/BaseFeature/Sources/Views/CurrentPlaylistTableViewCell.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/CurrentPlaylistTableViewCell.swift
@@ -11,15 +11,17 @@ class CurrentPlaylistTableViewCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- self.backgroundColor = DesignSystemAsset.BlueGrayColor.gray100.color
- self.playlistImageView.layer.cornerRadius = 4
- self.playlistNameLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 14)
- self.playlistNameLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
- self.playlistNameLabel.setTextWithAttributes(kernValue: -0.5)
- self.playlistCountLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
- self.playlistCountLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
- self.playlistCountLabel.setTextWithAttributes(kernValue: -0.5)
- self.lockImageView.image = DesignSystemAsset.Storage.storageClose.image
+ Task { @MainActor in
+ self.backgroundColor = DesignSystemAsset.BlueGrayColor.gray100.color
+ self.playlistImageView.layer.cornerRadius = 4
+ self.playlistNameLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 14)
+ self.playlistNameLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
+ self.playlistNameLabel.setTextWithAttributes(kernValue: -0.5)
+ self.playlistCountLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
+ self.playlistCountLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
+ self.playlistCountLabel.setTextWithAttributes(kernValue: -0.5)
+ self.lockImageView.image = DesignSystemAsset.Storage.storageClose.image
+ }
}
}
diff --git a/Projects/Features/BaseFeature/Sources/Views/EditSheetView.swift b/Projects/Features/BaseFeature/Sources/Views/EditSheetView.swift
index bebed910f..4a4194e82 100644
--- a/Projects/Features/BaseFeature/Sources/Views/EditSheetView.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/EditSheetView.swift
@@ -10,6 +10,7 @@ import DesignSystem
import UIKit
import Utility
+@MainActor
public protocol EditSheetViewDelegate: AnyObject {
func buttonTapped(type: EditSheetSelectType)
}
diff --git a/Projects/Features/BaseFeature/Sources/Views/NoticeCollectionViewCell.swift b/Projects/Features/BaseFeature/Sources/Views/NoticeCollectionViewCell.swift
index b08a1d9c2..0b478db15 100644
--- a/Projects/Features/BaseFeature/Sources/Views/NoticeCollectionViewCell.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/NoticeCollectionViewCell.swift
@@ -15,8 +15,10 @@ public final class NoticeCollectionViewCell: UICollectionViewCell {
override public func awakeFromNib() {
super.awakeFromNib()
- contentImageView.contentMode = .scaleAspectFill
- contentImageView.clipsToBounds = true
+ Task { @MainActor in
+ contentImageView.contentMode = .scaleAspectFill
+ contentImageView.clipsToBounds = true
+ }
}
}
diff --git a/Projects/Features/BaseFeature/Sources/Views/PlayButtonGroupView.swift b/Projects/Features/BaseFeature/Sources/Views/PlayButtonGroupView.swift
index 58c29b7de..1e03f6353 100644
--- a/Projects/Features/BaseFeature/Sources/Views/PlayButtonGroupView.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/PlayButtonGroupView.swift
@@ -14,6 +14,7 @@ public enum PlayEvent {
case shufflePlay
}
+@MainActor
public protocol PlayButtonGroupViewDelegate: AnyObject {
func play(_ event: PlayEvent)
}
diff --git a/Projects/Features/BaseFeature/Sources/Views/PlaylistEditSheetView.swift b/Projects/Features/BaseFeature/Sources/Views/PlaylistEditSheetView.swift
index 2f73288fa..6fab82903 100644
--- a/Projects/Features/BaseFeature/Sources/Views/PlaylistEditSheetView.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/PlaylistEditSheetView.swift
@@ -4,6 +4,7 @@ import Then
import UIKit
import Utility
+@MainActor
public protocol PlaylistEditSheetDelegate: AnyObject {
func didTap(_ type: PlaylistEditType)
}
diff --git a/Projects/Features/BaseFeature/Sources/Views/RecommendPlayListCell.swift b/Projects/Features/BaseFeature/Sources/Views/RecommendPlayListCell.swift
index 89078765b..5bd4c7d9b 100644
--- a/Projects/Features/BaseFeature/Sources/Views/RecommendPlayListCell.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/RecommendPlayListCell.swift
@@ -19,14 +19,16 @@ public class RecommendPlayListCell: UICollectionViewCell {
override public func awakeFromNib() {
super.awakeFromNib()
- self.contentView.layer.cornerRadius = 8
- self.contentView.layer.borderColor = UIColor.white.cgColor
- self.contentView.layer.borderWidth = 1
- self.contentView.backgroundColor = DesignSystemAsset.GrayColor.gray25.color
+ Task { @MainActor in
+ self.contentView.layer.cornerRadius = 8
+ self.contentView.layer.borderColor = UIColor.white.cgColor
+ self.contentView.layer.borderWidth = 1
+ self.contentView.backgroundColor = DesignSystemAsset.GrayColor.gray25.color
- let itemWidth: CGFloat = (APP_WIDTH() - (20 + 8 + 20)) / 2.0
- let itemHeight: CGFloat = (80.0 * itemWidth) / 164.0
- self.logoImageView.layer.cornerRadius = ((48 * itemHeight) / 80.0) / 2.0
+ let itemWidth: CGFloat = (APP_WIDTH() - (20 + 8 + 20)) / 2.0
+ let itemHeight: CGFloat = (80.0 * itemWidth) / 164.0
+ self.logoImageView.layer.cornerRadius = ((48 * itemHeight) / 80.0) / 2.0
+ }
}
}
diff --git a/Projects/Features/BaseFeature/Sources/Views/RecommendPlayListView.swift b/Projects/Features/BaseFeature/Sources/Views/RecommendPlayListView.swift
index ce06dac83..23dcea7ba 100644
--- a/Projects/Features/BaseFeature/Sources/Views/RecommendPlayListView.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/RecommendPlayListView.swift
@@ -11,6 +11,7 @@ import PlaylistDomainInterface
import UIKit
import Utility
+@MainActor
public protocol RecommendPlayListViewDelegate: AnyObject {
func itemSelected(model: RecommendPlaylistEntity)
}
diff --git a/Projects/Features/BaseFeature/Sources/Views/SongCartView.swift b/Projects/Features/BaseFeature/Sources/Views/SongCartView.swift
index 57426af90..ced915c4a 100644
--- a/Projects/Features/BaseFeature/Sources/Views/SongCartView.swift
+++ b/Projects/Features/BaseFeature/Sources/Views/SongCartView.swift
@@ -10,6 +10,7 @@ import DesignSystem
import UIKit
import Utility
+@MainActor
public protocol SongCartViewDelegate: AnyObject {
func buttonTapped(type: SongCartSelectType)
}
diff --git a/Projects/Features/BaseFeature/Testing/PrivacyComponentStub.swift b/Projects/Features/BaseFeature/Testing/PrivacyComponentStub.swift
index f7a3ac181..30e53b004 100644
--- a/Projects/Features/BaseFeature/Testing/PrivacyComponentStub.swift
+++ b/Projects/Features/BaseFeature/Testing/PrivacyComponentStub.swift
@@ -2,7 +2,7 @@
import BaseFeatureInterface
import UIKit
-public final class PrivacyComponentStub: PrivacyFactory {
+public final class PrivacyComponentStub: PrivacyFactory, @unchecked Sendable {
public func makeView() -> UIViewController {
return ContractViewController.viewController(type: .privacy)
}
diff --git a/Projects/Features/BaseFeature/Testing/ServiceTermsComponentStub.swift b/Projects/Features/BaseFeature/Testing/ServiceTermsComponentStub.swift
index 029651015..a654046dd 100644
--- a/Projects/Features/BaseFeature/Testing/ServiceTermsComponentStub.swift
+++ b/Projects/Features/BaseFeature/Testing/ServiceTermsComponentStub.swift
@@ -2,7 +2,7 @@
import BaseFeatureInterface
import UIKit
-public final class ServiceTermComponentStub: ServiceTermFactory {
+public final class ServiceTermComponentStub: ServiceTermFactory, @unchecked Sendable {
public func makeView() -> UIViewController {
return ContractViewController.viewController(type: .service)
}
diff --git a/Projects/Features/BaseFeature/Testing/TextPopUpComponentStub.swift b/Projects/Features/BaseFeature/Testing/TextPopUpComponentStub.swift
index 5c4324243..5acd8e830 100644
--- a/Projects/Features/BaseFeature/Testing/TextPopUpComponentStub.swift
+++ b/Projects/Features/BaseFeature/Testing/TextPopUpComponentStub.swift
@@ -2,7 +2,7 @@
import BaseFeatureInterface
import UIKit
-public final class TextPopupComponentStub: TextPopupFactory {
+public final class TextPopupComponentStub: TextPopupFactory, @unchecked Sendable {
public func makeView(
text: String?,
cancelButtonIsHidden: Bool,
diff --git a/Projects/Features/ChartFeature/Interface/ChartFactory.swift b/Projects/Features/ChartFeature/Interface/ChartFactory.swift
index 22aa0b352..307154465 100644
--- a/Projects/Features/ChartFeature/Interface/ChartFactory.swift
+++ b/Projects/Features/ChartFeature/Interface/ChartFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol ChartFactory {
func makeView() -> UIViewController
}
diff --git a/Projects/Features/ChartFeature/Sources/Components/ChartContentComponent.swift b/Projects/Features/ChartFeature/Sources/Components/ChartContentComponent.swift
index 7e6291d00..b3dafa9d4 100644
--- a/Projects/Features/ChartFeature/Sources/Components/ChartContentComponent.swift
+++ b/Projects/Features/ChartFeature/Sources/Components/ChartContentComponent.swift
@@ -13,6 +13,7 @@ public protocol ChartContentDependency: Dependency {
var songDetailPresenter: any SongDetailPresentable { get }
}
+@MainActor
public final class ChartContentComponent: Component {
public func makeView(type: ChartDateType) -> ChartContentViewController {
return ChartContentViewController.viewController(
diff --git a/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartContentViewController.swift b/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartContentViewController.swift
index a4621acd7..6255584e6 100644
--- a/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartContentViewController.swift
+++ b/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartContentViewController.swift
@@ -12,7 +12,8 @@ import Then
import UIKit
import Utility
-public final class ChartContentViewController: BaseViewController, ViewControllerFromStoryBoard, SongCartViewType {
+public final class ChartContentViewController: BaseViewController, ViewControllerFromStoryBoard,
+ @preconcurrency SongCartViewType {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var activityIncidator: NVActivityIndicatorView!
@@ -279,7 +280,7 @@ extension ChartContentViewController: SongCartViewDelegate {
case .addSong:
let log = CommonAnalyticsLog.clickAddMusicsButton(location: .chart)
LogManager.analytics(log)
- if PreferenceManager.userInfo == nil {
+ if PreferenceManager.shared.userInfo == nil {
output.showLogin.onNext(())
return
}
diff --git a/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartPlayPopupViewController.swift b/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartPlayPopupViewController.swift
index ddbf839bb..56d72432a 100644
--- a/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartPlayPopupViewController.swift
+++ b/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartPlayPopupViewController.swift
@@ -4,6 +4,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
public protocol ChartPlayPopupViewControllerDelegate: AnyObject {
func playTapped(type: HalfPlayType)
}
diff --git a/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartViewController.swift b/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartViewController.swift
index 1c704d919..4d85711c5 100644
--- a/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartViewController.swift
+++ b/Projects/Features/ChartFeature/Sources/ViewContrillers/ChartViewController.swift
@@ -110,7 +110,7 @@ private extension ChartViewController {
}
}
-extension ChartViewController: PageboyViewControllerDataSource, TMBarDataSource {
+extension ChartViewController: @preconcurrency PageboyViewControllerDataSource, @preconcurrency TMBarDataSource {
public func barItem(for bar: TMBar, at index: Int) -> TMBarItemable {
switch index {
case 0:
diff --git a/Projects/Features/ChartFeature/Sources/ViewModels/ChartContentViewModel.swift b/Projects/Features/ChartFeature/Sources/ViewModels/ChartContentViewModel.swift
index 4bba3ea9f..768c4179f 100644
--- a/Projects/Features/ChartFeature/Sources/ViewModels/ChartContentViewModel.swift
+++ b/Projects/Features/ChartFeature/Sources/ViewModels/ChartContentViewModel.swift
@@ -86,7 +86,7 @@ public final class ChartContentViewModel: ViewModelType {
.bind(to: output.indexOfSelectedSongs)
.disposed(by: disposeBag)
- Utility.PreferenceManager.$startPage
+ Utility.PreferenceManager.shared.$startPage
.skip(1)
.map { _ in [] }
.bind(to: output.indexOfSelectedSongs)
diff --git a/Projects/Features/ChartFeature/Sources/Views/ChartContentTableViewCell.swift b/Projects/Features/ChartFeature/Sources/Views/ChartContentTableViewCell.swift
index f702096ae..f6d211ff8 100644
--- a/Projects/Features/ChartFeature/Sources/Views/ChartContentTableViewCell.swift
+++ b/Projects/Features/ChartFeature/Sources/Views/ChartContentTableViewCell.swift
@@ -8,6 +8,7 @@ import Then
import UIKit
import Utility
+@MainActor
protocol ChartContentTableViewCellDelegate: AnyObject {
func tappedThumbnail(id: String)
}
diff --git a/Projects/Features/ChartFeature/Sources/Views/PlayButtonForChartView.swift b/Projects/Features/ChartFeature/Sources/Views/PlayButtonForChartView.swift
index 9642173b7..8c72fa1da 100644
--- a/Projects/Features/ChartFeature/Sources/Views/PlayButtonForChartView.swift
+++ b/Projects/Features/ChartFeature/Sources/Views/PlayButtonForChartView.swift
@@ -5,11 +5,12 @@ import SnapKit
import Then
import UIKit
-public enum PlayEvent {
+public enum PlayEvent: Sendable {
case allPlay
case shufflePlay
}
+@MainActor
public protocol PlayButtonForChartViewDelegate: AnyObject {
func pressPlay(_ event: PlayEvent)
}
diff --git a/Projects/Features/CreditSongListFeature/Demo/Sources/AppDelegate.swift b/Projects/Features/CreditSongListFeature/Demo/Sources/AppDelegate.swift
index 6c7849559..607653d8a 100644
--- a/Projects/Features/CreditSongListFeature/Demo/Sources/AppDelegate.swift
+++ b/Projects/Features/CreditSongListFeature/Demo/Sources/AppDelegate.swift
@@ -81,7 +81,7 @@ final class FakeCreditSongListTabItemFactory: CreditSongListTabItemFactory {
}
}
-final class DummySongDetailPresenter: SongDetailPresentable {
+final class DummySongDetailPresenter: SongDetailPresentable, @unchecked Sendable {
var presentSongDetailObservable: RxSwift.Observable<(ids: [String], selectedID: String)> {
.empty()
}
@@ -91,7 +91,7 @@ final class DummySongDetailPresenter: SongDetailPresentable {
func present(ids: [String], selectedID: String) {}
}
-final class DummyContainSongsFactory: ContainSongsFactory {
+final class DummyContainSongsFactory: ContainSongsFactory, @unchecked Sendable {
func makeView(songs: [String]) -> UIViewController {
let viewController = UIViewController()
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
@@ -101,13 +101,13 @@ final class DummyContainSongsFactory: ContainSongsFactory {
}
}
-final class DummySignInFactory: SignInFactory {
+final class DummySignInFactory: SignInFactory, @unchecked Sendable {
func makeView() -> UIViewController {
return UIViewController()
}
}
-final class DummyTextPopupFactory: TextPopupFactory {
+final class DummyTextPopupFactory: TextPopupFactory, @unchecked Sendable {
func makeView(
text: String?,
cancelButtonIsHidden: Bool,
diff --git a/Projects/Features/CreditSongListFeature/Interface/CreditSongListFactory.swift b/Projects/Features/CreditSongListFeature/Interface/CreditSongListFactory.swift
index 100b3e0ad..6e9d5c51a 100644
--- a/Projects/Features/CreditSongListFeature/Interface/CreditSongListFactory.swift
+++ b/Projects/Features/CreditSongListFeature/Interface/CreditSongListFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol CreditSongListFactory {
func makeViewController(workerName: String) -> UIViewController
}
diff --git a/Projects/Features/CreditSongListFeature/Interface/CreditSongListTabFactory.swift b/Projects/Features/CreditSongListFeature/Interface/CreditSongListTabFactory.swift
index ddf166b74..2eb71ca7e 100644
--- a/Projects/Features/CreditSongListFeature/Interface/CreditSongListTabFactory.swift
+++ b/Projects/Features/CreditSongListFeature/Interface/CreditSongListTabFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol CreditSongListTabFactory {
func makeViewController(workerName: String) -> UIViewController
}
diff --git a/Projects/Features/CreditSongListFeature/Interface/CreditSongListTabItemFactory.swift b/Projects/Features/CreditSongListFeature/Interface/CreditSongListTabItemFactory.swift
index fde4ff1d2..93a32a50c 100644
--- a/Projects/Features/CreditSongListFeature/Interface/CreditSongListTabItemFactory.swift
+++ b/Projects/Features/CreditSongListFeature/Interface/CreditSongListTabItemFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol CreditSongListTabItemFactory {
func makeViewController(workerName: String, sortType: CreditSongSortType) -> UIViewController
}
diff --git a/Projects/Features/CreditSongListFeature/Sources/CreditSongList/View/CreditProfileView.swift b/Projects/Features/CreditSongListFeature/Sources/CreditSongList/View/CreditProfileView.swift
index b7110981f..66dff77c4 100644
--- a/Projects/Features/CreditSongListFeature/Sources/CreditSongList/View/CreditProfileView.swift
+++ b/Projects/Features/CreditSongListFeature/Sources/CreditSongList/View/CreditProfileView.swift
@@ -5,6 +5,7 @@ import Then
import UIKit
import Utility
+@MainActor
protocol CreditProfileViewStateProtocol {
func updateProfile(entity: CreditProfileEntity)
}
diff --git a/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabItemReactor.swift b/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabItemReactor.swift
index 98a152052..a39c43f26 100644
--- a/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabItemReactor.swift
+++ b/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabItemReactor.swift
@@ -180,7 +180,7 @@ private extension CreditSongListTabItemReactor {
}
func addSongButtonDidTap() -> Observable {
- guard PreferenceManager.userInfo != nil else {
+ guard PreferenceManager.shared.userInfo != nil else {
return navigateMutation(
navigateType: .textPopup(
text: LocalizationStrings.needLoginWarning,
diff --git a/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabItemViewController.swift b/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabItemViewController.swift
index 37acd281f..038ec18f3 100644
--- a/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabItemViewController.swift
+++ b/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabItemViewController.swift
@@ -11,7 +11,7 @@ import Utility
final class CreditSongListTabItemViewController:
BaseReactorViewController,
- SongCartViewType {
+ @preconcurrency SongCartViewType {
var songCartView: SongCartView!
var bottomSheetView: BottomSheetView!
diff --git a/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabViewController.swift b/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabViewController.swift
index f408b43fa..19b0bcf5b 100644
--- a/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabViewController.swift
+++ b/Projects/Features/CreditSongListFeature/Sources/CreditSongListTab/CreditSongListTabViewController.swift
@@ -92,7 +92,7 @@ private extension CreditSongListTabViewController {
}
}
-extension CreditSongListTabViewController: PageboyViewControllerDataSource {
+extension CreditSongListTabViewController: @preconcurrency PageboyViewControllerDataSource {
func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> Int {
sortTypes.count
}
@@ -109,7 +109,7 @@ extension CreditSongListTabViewController: PageboyViewControllerDataSource {
}
}
-extension CreditSongListTabViewController: TMBarDataSource {
+extension CreditSongListTabViewController: @preconcurrency TMBarDataSource {
func barItem(for bar: any TMBar, at index: Int) -> any TMBarItemable {
guard let sortItem = sortTypes[safe: index] else { return TMBarItem(title: "") }
diff --git a/Projects/Features/CreditSongListFeature/Sources/ScopedState/CreditSongListScopedState.swift b/Projects/Features/CreditSongListFeature/Sources/ScopedState/CreditSongListScopedState.swift
index 746bebc9c..17e393802 100644
--- a/Projects/Features/CreditSongListFeature/Sources/ScopedState/CreditSongListScopedState.swift
+++ b/Projects/Features/CreditSongListFeature/Sources/ScopedState/CreditSongListScopedState.swift
@@ -1,9 +1,9 @@
import Foundation
import RxCocoa
-import RxSwift
+@preconcurrency import RxSwift
import UIKit
-final class CreditSongListScopedState {
+final class CreditSongListScopedState: Sendable {
static let shared = CreditSongListScopedState()
private init() {}
diff --git a/Projects/Features/FruitDrawFeature/Interface/FruitDrawFactory.swift b/Projects/Features/FruitDrawFeature/Interface/FruitDrawFactory.swift
index 48d843dce..45d9e4b9a 100644
--- a/Projects/Features/FruitDrawFeature/Interface/FruitDrawFactory.swift
+++ b/Projects/Features/FruitDrawFeature/Interface/FruitDrawFactory.swift
@@ -1,9 +1,11 @@
import UIKit
+@MainActor
public protocol FruitDrawViewControllerDelegate: AnyObject {
func completedFruitDraw(itemCount: Int)
}
+@MainActor
public protocol FruitDrawFactory {
func makeView(delegate: FruitDrawViewControllerDelegate) -> UIViewController
}
diff --git a/Projects/Features/FruitDrawFeature/Interface/FruitStorageFactory.swift b/Projects/Features/FruitDrawFeature/Interface/FruitStorageFactory.swift
index 4079e460b..691f88ec1 100644
--- a/Projects/Features/FruitDrawFeature/Interface/FruitStorageFactory.swift
+++ b/Projects/Features/FruitDrawFeature/Interface/FruitStorageFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol FruitStorageFactory {
func makeView() -> UIViewController
}
diff --git a/Projects/Features/FruitDrawFeature/Sources/Views/FruitListCell.swift b/Projects/Features/FruitDrawFeature/Sources/Views/FruitListCell.swift
index 15bb5cbbb..ab5b9805c 100644
--- a/Projects/Features/FruitDrawFeature/Sources/Views/FruitListCell.swift
+++ b/Projects/Features/FruitDrawFeature/Sources/Views/FruitListCell.swift
@@ -3,6 +3,7 @@ import UIKit
import UserDomainInterface
import Utility
+@MainActor
public protocol FruitListCellDelegate: AnyObject {
func itemSelected(item: FruitEntity)
}
diff --git a/Projects/Features/HomeFeature/Interface/HomeFactory.swift b/Projects/Features/HomeFeature/Interface/HomeFactory.swift
index 4150d1f89..82a91b1ad 100644
--- a/Projects/Features/HomeFeature/Interface/HomeFactory.swift
+++ b/Projects/Features/HomeFeature/Interface/HomeFactory.swift
@@ -1,6 +1,7 @@
import Foundation
import UIKit
+@MainActor
public protocol HomeFactory {
func makeView() -> UIViewController
}
diff --git a/Projects/Features/HomeFeature/Sources/Components/NewSongsComponent.swift b/Projects/Features/HomeFeature/Sources/Components/NewSongsComponent.swift
index 0d29afde5..f14e20f56 100644
--- a/Projects/Features/HomeFeature/Sources/Components/NewSongsComponent.swift
+++ b/Projects/Features/HomeFeature/Sources/Components/NewSongsComponent.swift
@@ -5,6 +5,7 @@ public protocol NewSongsDependency: Dependency {
var newSongsContentComponent: NewSongsContentComponent { get }
}
+@MainActor
public final class NewSongsComponent: Component {
public func makeView() -> NewSongsViewController {
return NewSongsViewController.viewController(newSongsContentComponent: dependency.newSongsContentComponent)
diff --git a/Projects/Features/HomeFeature/Sources/Components/NewSongsContentComponent.swift b/Projects/Features/HomeFeature/Sources/Components/NewSongsContentComponent.swift
index 530926b4c..150962d0f 100644
--- a/Projects/Features/HomeFeature/Sources/Components/NewSongsContentComponent.swift
+++ b/Projects/Features/HomeFeature/Sources/Components/NewSongsContentComponent.swift
@@ -15,6 +15,7 @@ public protocol NewSongsContentDependency: Dependency {
var songDetailPresenter: any SongDetailPresentable { get }
}
+@MainActor
public final class NewSongsContentComponent: Component {
public func makeView(type: NewSongGroupType) -> NewSongsContentViewController {
return NewSongsContentViewController.viewController(
diff --git a/Projects/Features/HomeFeature/Sources/ViewControllers/HomeViewController.swift b/Projects/Features/HomeFeature/Sources/ViewControllers/HomeViewController.swift
index 86ccdc97b..fda71071d 100644
--- a/Projects/Features/HomeFeature/Sources/ViewControllers/HomeViewController.swift
+++ b/Projects/Features/HomeFeature/Sources/ViewControllers/HomeViewController.swift
@@ -457,13 +457,15 @@ extension HomeViewController: RecommendPlayListViewDelegate {
}
public extension HomeViewController {
- func equalHandleTapped() {
- let viewControllersCount: Int = self.navigationController?.viewControllers.count ?? 0
- if viewControllersCount > 1 {
- self.navigationController?.popToRootViewController(animated: true)
- } else {
- guard let scrollView = self.scrollView else { return }
- scrollView.setContentOffset(CGPoint(x: 0, y: -STATUS_BAR_HEGHIT()), animated: true)
+ nonisolated func equalHandleTapped() {
+ Task { @MainActor in
+ let viewControllersCount: Int = self.navigationController?.viewControllers.count ?? 0
+ if viewControllersCount > 1 {
+ self.navigationController?.popToRootViewController(animated: true)
+ } else {
+ guard let scrollView = self.scrollView else { return }
+ scrollView.setContentOffset(CGPoint(x: 0, y: -STATUS_BAR_HEGHIT()), animated: true)
+ }
}
}
}
diff --git a/Projects/Features/HomeFeature/Sources/ViewControllers/NewSongsContentViewController.swift b/Projects/Features/HomeFeature/Sources/ViewControllers/NewSongsContentViewController.swift
index 06f15d263..b26521b2f 100644
--- a/Projects/Features/HomeFeature/Sources/ViewControllers/NewSongsContentViewController.swift
+++ b/Projects/Features/HomeFeature/Sources/ViewControllers/NewSongsContentViewController.swift
@@ -11,7 +11,8 @@ import SongsDomainInterface
import UIKit
import Utility
-public class NewSongsContentViewController: UIViewController, ViewControllerFromStoryBoard, SongCartViewType {
+public class NewSongsContentViewController: UIViewController, ViewControllerFromStoryBoard,
+ @preconcurrency SongCartViewType {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var activityIncidator: NVActivityIndicatorView!
@@ -285,7 +286,7 @@ extension NewSongsContentViewController: SongCartViewDelegate {
let log = CommonAnalyticsLog.clickAddMusicsButton(location: .recentMusic)
LogManager.analytics(log)
- if PreferenceManager.userInfo == nil {
+ if PreferenceManager.shared.userInfo == nil {
output.showLogin.onNext(())
return
}
@@ -332,8 +333,10 @@ extension NewSongsContentViewController: SongCartViewDelegate {
extension Reactive where Base: NewSongsContentViewController {
var loadMore: Binder {
return Binder(base) { viewController, _ in
- let pageID = viewController.input.pageID.value
- viewController.input.pageID.accept(pageID + 1)
+ Task { @MainActor in
+ let pageID = viewController.input.pageID.value
+ viewController.input.pageID.accept(pageID + 1)
+ }
}
}
}
diff --git a/Projects/Features/HomeFeature/Sources/ViewControllers/NewSongsViewController.swift b/Projects/Features/HomeFeature/Sources/ViewControllers/NewSongsViewController.swift
index 770c84f49..ef19febd2 100644
--- a/Projects/Features/HomeFeature/Sources/ViewControllers/NewSongsViewController.swift
+++ b/Projects/Features/HomeFeature/Sources/ViewControllers/NewSongsViewController.swift
@@ -112,7 +112,7 @@ extension NewSongsViewController {
}
}
-extension NewSongsViewController: PageboyViewControllerDataSource, TMBarDataSource {
+extension NewSongsViewController: @preconcurrency PageboyViewControllerDataSource, @preconcurrency TMBarDataSource {
public func barItem(for bar: TMBar, at index: Int) -> TMBarItemable {
switch index {
case 0:
diff --git a/Projects/Features/HomeFeature/Sources/ViewModels/NewSongsContentViewModel.swift b/Projects/Features/HomeFeature/Sources/ViewModels/NewSongsContentViewModel.swift
index 26b00ae4f..afac493aa 100644
--- a/Projects/Features/HomeFeature/Sources/ViewModels/NewSongsContentViewModel.swift
+++ b/Projects/Features/HomeFeature/Sources/ViewModels/NewSongsContentViewModel.swift
@@ -126,7 +126,7 @@ public final class NewSongsContentViewModel: ViewModelType {
.bind(to: output.indexOfSelectedSongs)
.disposed(by: disposeBag)
- Utility.PreferenceManager.$startPage
+ Utility.PreferenceManager.shared.$startPage
.skip(1)
.map { _ in [] }
.bind(to: output.indexOfSelectedSongs)
diff --git a/Projects/Features/HomeFeature/Sources/Views/HomeChartCell.swift b/Projects/Features/HomeFeature/Sources/Views/HomeChartCell.swift
index c44c2c4d8..80765557c 100644
--- a/Projects/Features/HomeFeature/Sources/Views/HomeChartCell.swift
+++ b/Projects/Features/HomeFeature/Sources/Views/HomeChartCell.swift
@@ -15,6 +15,7 @@ import SnapKit
import UIKit
import Utility
+@MainActor
protocol HomeChartCellDelegate: AnyObject {
func thumbnailDidTap(model: ChartRankingEntity)
func playButtonDidTap(model: ChartRankingEntity)
@@ -35,10 +36,12 @@ class HomeChartCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- albumImageView.layer.cornerRadius = 4
- albumImageView.contentMode = .scaleAspectFill
- playImageView.image = DesignSystemAsset.Home.playSmall.image
- bind()
+ Task { @MainActor in
+ albumImageView.layer.cornerRadius = 4
+ albumImageView.contentMode = .scaleAspectFill
+ playImageView.image = DesignSystemAsset.Home.playSmall.image
+ bind()
+ }
}
}
diff --git a/Projects/Features/HomeFeature/Sources/Views/HomeNewSongCell.swift b/Projects/Features/HomeFeature/Sources/Views/HomeNewSongCell.swift
index 0b290477d..93645e83a 100644
--- a/Projects/Features/HomeFeature/Sources/Views/HomeNewSongCell.swift
+++ b/Projects/Features/HomeFeature/Sources/Views/HomeNewSongCell.swift
@@ -14,6 +14,7 @@ import SongsDomainInterface
import UIKit
import Utility
+@MainActor
protocol HomeNewSongCellDelegate: AnyObject {
func thumbnailDidTap(model: NewSongsEntity)
func playButtonDidTap(model: NewSongsEntity)
@@ -32,14 +33,16 @@ final class HomeNewSongCell: UICollectionViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- self.backgroundColor = .clear
- self.contentView.backgroundColor = .clear
+ Task { @MainActor in
+ self.backgroundColor = .clear
+ self.contentView.backgroundColor = .clear
- albumImageView.layer.cornerRadius = 8
- albumImageView.clipsToBounds = true
- albumImageView.contentMode = .scaleAspectFill
- playImageView.image = DesignSystemAsset.Home.playSmall.image
- bind()
+ albumImageView.layer.cornerRadius = 8
+ albumImageView.clipsToBounds = true
+ albumImageView.contentMode = .scaleAspectFill
+ playImageView.image = DesignSystemAsset.Home.playSmall.image
+ bind()
+ }
}
}
diff --git a/Projects/Features/HomeFeature/Sources/Views/NewSongsCell.swift b/Projects/Features/HomeFeature/Sources/Views/NewSongsCell.swift
index 72e8fb9aa..5c1d4a307 100644
--- a/Projects/Features/HomeFeature/Sources/Views/NewSongsCell.swift
+++ b/Projects/Features/HomeFeature/Sources/Views/NewSongsCell.swift
@@ -4,6 +4,7 @@ import SongsDomainInterface
import UIKit
import Utility
+@MainActor
protocol NewSongsCellDelegate: AnyObject {
func tappedThumbnail(id: String)
}
@@ -20,10 +21,11 @@ class NewSongsCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- contentView.backgroundColor = .clear
- albumImageView.clipsToBounds = true
- albumImageView.layer.cornerRadius = 4
- albumImageView.contentMode = .scaleAspectFill
+ Task { @MainActor in
+ albumImageView.layer.cornerRadius = 4
+ albumImageView.clipsToBounds = true
+ albumImageView.contentMode = .scaleAspectFill
+ }
}
@IBAction func playButtonAction(_ sender: Any) {
diff --git a/Projects/Features/LyricHighlightingFeature/Interface/LyricHighlightingFactory.swift b/Projects/Features/LyricHighlightingFeature/Interface/LyricHighlightingFactory.swift
index 70ad81de4..28583f29c 100644
--- a/Projects/Features/LyricHighlightingFeature/Interface/LyricHighlightingFactory.swift
+++ b/Projects/Features/LyricHighlightingFeature/Interface/LyricHighlightingFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol LyricHighlightingFactory {
func makeView(model: LyricHighlightingRequiredModel) -> UIViewController
}
diff --git a/Projects/Features/LyricHighlightingFeature/Sources/Components/LyricDecoratingComponent.swift b/Projects/Features/LyricHighlightingFeature/Sources/Components/LyricDecoratingComponent.swift
index 3bd9f12aa..ccc993927 100644
--- a/Projects/Features/LyricHighlightingFeature/Sources/Components/LyricDecoratingComponent.swift
+++ b/Projects/Features/LyricHighlightingFeature/Sources/Components/LyricDecoratingComponent.swift
@@ -9,6 +9,7 @@ public protocol LyricDecoratingDependency: Dependency {
var textPopupFactory: any TextPopupFactory { get }
}
+@MainActor
public final class LyricDecoratingComponent: Component {
public func makeView(model: LyricHighlightingRequiredModel) -> LyricDecoratingViewController {
let viewModel = LyricDecoratingViewModel(
diff --git a/Projects/Features/LyricHighlightingFeature/Sources/ViewControllers/LyricDecoratingViewController.swift b/Projects/Features/LyricHighlightingFeature/Sources/ViewControllers/LyricDecoratingViewController.swift
index 59522ffc4..37ed6be56 100644
--- a/Projects/Features/LyricHighlightingFeature/Sources/ViewControllers/LyricDecoratingViewController.swift
+++ b/Projects/Features/LyricHighlightingFeature/Sources/ViewControllers/LyricDecoratingViewController.swift
@@ -317,19 +317,21 @@ private extension LyricDecoratingViewController {
}
public extension LyricDecoratingViewController {
- func showPhotoLibrary() {
- let image = decorateShareContentView.asImage(size: .init(width: 960, height: 960))
- PHPhotoLibrary.shared().performChanges {
- PHAssetChangeRequest.creationRequestForAsset(from: image)
- } completionHandler: { _, error in
- var message: String = ""
- if let error = error {
- message = error.localizedDescription
- } else {
- message = "ํด๋น ์ด๋ฏธ์ง๊ฐ ์ ์ฅ๋์์ต๋๋ค."
- }
- DispatchQueue.main.async {
- self.showToast(text: message, options: [.tabBar])
+ nonisolated func showPhotoLibrary() {
+ Task { @MainActor in
+ let image = decorateShareContentView.asImage(size: .init(width: 960, height: 960))
+ PHPhotoLibrary.shared().performChanges {
+ PHAssetChangeRequest.creationRequestForAsset(from: image)
+ } completionHandler: { _, error in
+ var message: String = ""
+ if let error = error {
+ message = error.localizedDescription
+ } else {
+ message = "ํด๋น ์ด๋ฏธ์ง๊ฐ ์ ์ฅ๋์์ต๋๋ค."
+ }
+ DispatchQueue.main.async {
+ self.showToast(text: message, options: [.tabBar])
+ }
}
}
}
diff --git a/Projects/Features/MainTabFeature/Sources/AppEntryState/AppEntryState.swift b/Projects/Features/MainTabFeature/Sources/AppEntryState/AppEntryState.swift
index 8db55cd2d..0228dc37d 100644
--- a/Projects/Features/MainTabFeature/Sources/AppEntryState/AppEntryState.swift
+++ b/Projects/Features/MainTabFeature/Sources/AppEntryState/AppEntryState.swift
@@ -1,12 +1,12 @@
import Foundation
import RxRelay
-public protocol AppEntryStateHandleable {
+public protocol AppEntryStateHandleable: Sendable {
var moveSceneObservable: BehaviorRelay<[String: Any]> { get }
func moveScene(params: [String: Any])
}
-public final class AppEntryState: AppEntryStateHandleable {
+public final class AppEntryState: AppEntryStateHandleable, @unchecked Sendable {
private let moveSceneRelay: BehaviorRelay<[String: Any]> = .init(value: [:])
public var moveSceneObservable: BehaviorRelay<[String: Any]> {
diff --git a/Projects/Features/MainTabFeature/Sources/Components/BottomTabBarComponent.swift b/Projects/Features/MainTabFeature/Sources/Components/BottomTabBarComponent.swift
index df7336485..461ed6486 100644
--- a/Projects/Features/MainTabFeature/Sources/Components/BottomTabBarComponent.swift
+++ b/Projects/Features/MainTabFeature/Sources/Components/BottomTabBarComponent.swift
@@ -3,6 +3,7 @@ import NeedleFoundation
public protocol BottomTabBarDependency: Dependency {}
+@MainActor
public final class BottomTabBarComponent: Component {
public func makeView() -> BottomTabBarViewController {
return BottomTabBarViewController.viewController()
diff --git a/Projects/Features/MainTabFeature/Sources/Components/MainContainerComponent.swift b/Projects/Features/MainTabFeature/Sources/Components/MainContainerComponent.swift
index b74fd80d2..578ab7729 100644
--- a/Projects/Features/MainTabFeature/Sources/Components/MainContainerComponent.swift
+++ b/Projects/Features/MainTabFeature/Sources/Components/MainContainerComponent.swift
@@ -11,6 +11,7 @@ public protocol MainContainerDependency: Dependency {
var playlistPresenterGlobalState: any PlayListPresenterGlobalStateProtocol { get }
}
+@MainActor
public final class MainContainerComponent: Component {
public func makeView() -> MainContainerViewController {
return MainContainerViewController
diff --git a/Projects/Features/MainTabFeature/Sources/Components/MainTabBarComponent.swift b/Projects/Features/MainTabFeature/Sources/Components/MainTabBarComponent.swift
index 8b50be05e..d9874b32c 100644
--- a/Projects/Features/MainTabFeature/Sources/Components/MainTabBarComponent.swift
+++ b/Projects/Features/MainTabFeature/Sources/Components/MainTabBarComponent.swift
@@ -30,6 +30,7 @@ public protocol MainTabBarDependency: Dependency {
var songDetailPresenter: any SongDetailPresentable { get }
}
+@MainActor
public final class MainTabBarComponent: Component {
public func makeView() -> MainTabBarViewController {
return MainTabBarViewController.viewController(
diff --git a/Projects/Features/MainTabFeature/Sources/Components/NoticePopupComponent.swift b/Projects/Features/MainTabFeature/Sources/Components/NoticePopupComponent.swift
index 5835ccc4b..08bae538d 100644
--- a/Projects/Features/MainTabFeature/Sources/Components/NoticePopupComponent.swift
+++ b/Projects/Features/MainTabFeature/Sources/Components/NoticePopupComponent.swift
@@ -12,6 +12,7 @@ import NoticeDomainInterface
public protocol NoticePopupDependency: Dependency {}
+@MainActor
public final class NoticePopupComponent: Component {
public func makeView(model: [FetchNoticeEntity]) -> NoticePopupViewController {
return NoticePopupViewController.viewController(
diff --git a/Projects/Features/MainTabFeature/Sources/ViewControllers/BottomTabBarViewController.swift b/Projects/Features/MainTabFeature/Sources/ViewControllers/BottomTabBarViewController.swift
index afc97c8fa..224e754ed 100644
--- a/Projects/Features/MainTabFeature/Sources/ViewControllers/BottomTabBarViewController.swift
+++ b/Projects/Features/MainTabFeature/Sources/ViewControllers/BottomTabBarViewController.swift
@@ -4,6 +4,7 @@ import RxSwift
import UIKit
import Utility
+@MainActor
protocol BottomTabBarViewDelegate: AnyObject {
func handleTapped(index previous: Int, current: Int)
func equalHandleTapped(index current: Int)
@@ -12,7 +13,7 @@ protocol BottomTabBarViewDelegate: AnyObject {
public final class BottomTabBarViewController: UIViewController, ViewControllerFromStoryBoard {
@IBOutlet weak var stackView: UIStackView!
- private var currentIndex = Utility.PreferenceManager.startPage ?? 0
+ private var currentIndex = Utility.PreferenceManager.shared.startPage ?? 0
weak var delegate: BottomTabBarViewDelegate?
private lazy var tabs: [TabItemView] = {
@@ -78,7 +79,7 @@ public final class BottomTabBarViewController: UIViewController, ViewControllerF
private extension BottomTabBarViewController {
func configureUI() {
- let startPage: Int = Utility.PreferenceManager.startPage ?? 0
+ let startPage: Int = Utility.PreferenceManager.shared.startPage ?? 0
LogManager.printDebug("startPage: \(startPage)")
for (index, model) in self.tabItems.enumerated() {
diff --git a/Projects/Features/MainTabFeature/Sources/ViewControllers/MainContainerViewController.swift b/Projects/Features/MainTabFeature/Sources/ViewControllers/MainContainerViewController.swift
index 11a0b654f..4b81ad395 100644
--- a/Projects/Features/MainTabFeature/Sources/ViewControllers/MainContainerViewController.swift
+++ b/Projects/Features/MainTabFeature/Sources/ViewControllers/MainContainerViewController.swift
@@ -55,7 +55,7 @@ private extension MainContainerViewController {
func setLayout() {
view.addSubview(playlistFloatingActionButton)
- let startPage: Int = PreferenceManager.startPage ?? 0
+ let startPage: Int = PreferenceManager.shared.startPage ?? 0
let bottomOffset: CGFloat = startPage == 3 ?
PlaylistFloatingButtonPosition.top.bottomOffset :
PlaylistFloatingButtonPosition.default.bottomOffset
@@ -174,7 +174,7 @@ private extension MainContainerViewController {
.disposed(by: disposeBag)
Observable.combineLatest(
- PreferenceManager.$startPage.map { $0 ?? 0 },
+ PreferenceManager.shared.$startPage.map { $0 ?? 0 },
NotificationCenter.default.rx
.notification(.shouldMovePlaylistFloatingButton)
.map { $0.object as? PlaylistFloatingButtonPosition ?? .default }
diff --git a/Projects/Features/MainTabFeature/Sources/ViewControllers/MainTabBarViewController.swift b/Projects/Features/MainTabFeature/Sources/ViewControllers/MainTabBarViewController.swift
index 84ddb57c1..c5d12cb0a 100644
--- a/Projects/Features/MainTabFeature/Sources/ViewControllers/MainTabBarViewController.swift
+++ b/Projects/Features/MainTabFeature/Sources/ViewControllers/MainTabBarViewController.swift
@@ -18,11 +18,13 @@ import StorageFeatureInterface
import UIKit
import Utility
-public final class MainTabBarViewController: BaseViewController, ViewControllerFromStoryBoard, ContainerViewType {
+public final class MainTabBarViewController: BaseViewController,
+ ViewControllerFromStoryBoard,
+ @preconcurrency ContainerViewType {
@IBOutlet public weak var contentView: UIView!
private var previousIndex: Int?
- private var selectedIndex: Int = Utility.PreferenceManager.startPage ?? 0
+ private var selectedIndex: Int = Utility.PreferenceManager.shared.startPage ?? 0
private lazy var viewControllers: [UIViewController] = {
return [
homeFactory.makeView().wrapNavigationController,
@@ -208,35 +210,31 @@ private extension MainTabBarViewController {
private extension MainTabBarViewController {
func requestNotificationAuthorization() {
- Messaging.messaging().delegate = self
- UNUserNotificationCenter.current().delegate = self
-
- let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
- UNUserNotificationCenter.current().requestAuthorization(
- options: authOptions,
- completionHandler: { granted, _ in
- if granted {
- DispatchQueue.main.async {
- UIApplication.shared.registerForRemoteNotifications()
- }
- LogManager.printDebug("๐:: Notification authorized: \(Messaging.messaging().fcmToken ?? "")")
- } else {
- LogManager.printDebug("๐:: Notification denied")
- }
- PreferenceManager.pushNotificationAuthorizationStatus = granted
+ Task { @MainActor in
+ Messaging.messaging().delegate = self
+ UNUserNotificationCenter.current().delegate = self
+
+ let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
+ let granted = try await UNUserNotificationCenter.current().requestAuthorization(options: authOptions)
+ if granted {
+ UIApplication.shared.registerForRemoteNotifications()
+ LogManager.printDebug("๐:: Notification authorized: \(Messaging.messaging().fcmToken ?? "")")
+ } else {
+ LogManager.printDebug("๐:: Notification denied")
}
- )
+ PreferenceManager.shared.pushNotificationAuthorizationStatus = granted
+ }
}
func configureUI() {
- let startPage: Int = Utility.PreferenceManager.startPage ?? 0
+ let startPage: Int = Utility.PreferenceManager.shared.startPage ?? 0
add(asChildViewController: viewControllers[startPage])
}
}
extension MainTabBarViewController {
func updateContent(previous: Int, current: Int) {
- Utility.PreferenceManager.startPage = current
+ Utility.PreferenceManager.shared.startPage = current
remove(asChildViewController: viewControllers[previous])
add(asChildViewController: viewControllers[current])
@@ -268,7 +266,7 @@ extension MainTabBarViewController: NoticePopupViewControllerDelegate {
}
extension MainTabBarViewController: UNUserNotificationCenterDelegate {
- public func userNotificationCenter(
+ public nonisolated func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification
) async -> UNNotificationPresentationOptions {
@@ -284,12 +282,12 @@ extension MainTabBarViewController: UNUserNotificationCenterDelegate {
return [[.list, .banner, .sound]]
}
- public func userNotificationCenter(
+ public nonisolated func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse
) async {
let userInfo = response.notification.request.content.userInfo
- appEntryState.moveScene(params: userInfo.parseNotificationInfo)
+ await appEntryState.moveScene(params: userInfo.parseNotificationInfo)
// With swizzling disabled you must let Messaging know about the message, for Analytics
Messaging.messaging().appDidReceiveMessage(userInfo)
@@ -301,10 +299,12 @@ extension MainTabBarViewController: UNUserNotificationCenterDelegate {
extension MainTabBarViewController: MessagingDelegate {
/// [START refresh_token]
- public func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
+ public nonisolated func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
LogManager.printDebug("๐:: Firebase registration token: \(String(describing: fcmToken ?? "-"))")
// If necessary send token to application server.
- input.detectedRefreshPushToken.onNext(())
+ Task { @MainActor in
+ input.detectedRefreshPushToken.onNext(())
+ }
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
// [END refresh_token]
diff --git a/Projects/Features/MainTabFeature/Sources/ViewControllers/NoticePopupViewController.swift b/Projects/Features/MainTabFeature/Sources/ViewControllers/NoticePopupViewController.swift
index 4b4285800..b60c91489 100644
--- a/Projects/Features/MainTabFeature/Sources/ViewControllers/NoticePopupViewController.swift
+++ b/Projects/Features/MainTabFeature/Sources/ViewControllers/NoticePopupViewController.swift
@@ -17,6 +17,7 @@ import Then
import UIKit
import Utility
+@MainActor
public protocol NoticePopupViewControllerDelegate: AnyObject {
func noticeTapped(model: FetchNoticeEntity)
}
@@ -59,13 +60,13 @@ public class NoticePopupViewController: UIViewController, ViewControllerFromStor
}
@IBAction func ignoreButtonAction(_ sender: Any) {
- let savedIgoredNoticeIds: [Int] = Utility.PreferenceManager.ignoredPopupIDs ?? []
+ let savedIgoredNoticeIds: [Int] = Utility.PreferenceManager.shared.ignoredPopupIDs ?? []
let currentNoticeIds: [Int] = output.originDataSource.value.map { $0.id }
if savedIgoredNoticeIds.isEmpty {
- Utility.PreferenceManager.ignoredPopupIDs = currentNoticeIds
+ Utility.PreferenceManager.shared.ignoredPopupIDs = currentNoticeIds
} else {
- Utility.PreferenceManager.ignoredPopupIDs = savedIgoredNoticeIds + currentNoticeIds
+ Utility.PreferenceManager.shared.ignoredPopupIDs = savedIgoredNoticeIds + currentNoticeIds
}
dismiss(animated: true)
}
diff --git a/Projects/Features/MainTabFeature/Sources/ViewModels/MainTabBarViewModel.swift b/Projects/Features/MainTabFeature/Sources/ViewModels/MainTabBarViewModel.swift
index 87722e9ee..b9e7984d2 100644
--- a/Projects/Features/MainTabFeature/Sources/ViewModels/MainTabBarViewModel.swift
+++ b/Projects/Features/MainTabFeature/Sources/ViewModels/MainTabBarViewModel.swift
@@ -4,7 +4,7 @@ import LogManager
import NoticeDomainInterface
import NotificationDomainInterface
import RxRelay
-import RxSwift
+@preconcurrency import RxSwift
import SongsDomainInterface
import Utility
@@ -14,7 +14,7 @@ private typealias Observer = (
grantedNotificationAuthorization: Bool
)
-public final class MainTabBarViewModel {
+public final class MainTabBarViewModel: Sendable {
private let fetchNoticePopupUseCase: FetchNoticePopupUseCase
private let fetchNoticeIDListUseCase: FetchNoticeIDListUseCase
private let updateNotificationTokenUseCase: UpdateNotificationTokenUseCase
@@ -45,7 +45,7 @@ public final class MainTabBarViewModel {
public func transform(from input: Input) -> Output {
let output = Output()
- let ignoredPopupIDs: [Int] = Utility.PreferenceManager.ignoredPopupIDs ?? []
+ let ignoredPopupIDs: [Int] = Utility.PreferenceManager.shared.ignoredPopupIDs ?? []
DEBUG_LOG("ignoredPopupIDs: \(ignoredPopupIDs)")
input.fetchNoticePopup
@@ -64,7 +64,7 @@ public final class MainTabBarViewModel {
.disposed(by: disposeBag)
input.fetchNoticeIDList
- .withLatestFrom(PreferenceManager.$readNoticeIDs)
+ .withLatestFrom(PreferenceManager.shared.$readNoticeIDs)
.filter { ($0 ?? []).isEmpty }
.flatMap { [fetchNoticeIDListUseCase] _ -> Single in
return fetchNoticeIDListUseCase.execute()
@@ -72,15 +72,15 @@ public final class MainTabBarViewModel {
}
.map { $0.data }
.bind { allNoticeIDs in
- PreferenceManager.readNoticeIDs = allNoticeIDs
+ PreferenceManager.shared.readNoticeIDs = allNoticeIDs
}
.disposed(by: disposeBag)
// ํธ์ถ ์กฐ๊ฑด: ์ฑ ์คํ ์ 1ํ, ๋ฆฌํ๋ ์ฌ ํ ํฐ ๊ฐ์ง, ๊ธฐ๊ธฐ์๋ฆผ on/off
Observable.combineLatest(
input.detectedRefreshPushToken,
- PreferenceManager.$userInfo.map { $0?.ID }.distinctUntilChanged(),
- PreferenceManager.$pushNotificationAuthorizationStatus.distinctUntilChanged().map { $0 ?? false }
+ PreferenceManager.shared.$userInfo.map { $0?.ID }.distinctUntilChanged(),
+ PreferenceManager.shared.$pushNotificationAuthorizationStatus.distinctUntilChanged().map { $0 ?? false }
) { detected, id, granted -> Observer in
return Observer(
detectedRefreshPushToken: detected,
diff --git a/Projects/Features/MainTabFeature/Sources/Views/TabItemView.swift b/Projects/Features/MainTabFeature/Sources/Views/TabItemView.swift
index a1a165e31..50e9aa6f0 100644
--- a/Projects/Features/MainTabFeature/Sources/Views/TabItemView.swift
+++ b/Projects/Features/MainTabFeature/Sources/Views/TabItemView.swift
@@ -13,6 +13,7 @@ import SnapKit
import UIKit
import Utility
+@MainActor
protocol TabItemViewDelegate: AnyObject {
func handleTap(view: TabItemView)
}
@@ -48,7 +49,9 @@ final class TabItemView: UIView {
override func awakeFromNib() {
super.awakeFromNib()
- self.addTapGesture()
+ Task { @MainActor in
+ self.addTapGesture()
+ }
}
}
diff --git a/Projects/Features/MusicDetailFeature/Demo/Sources/AppDelegate.swift b/Projects/Features/MusicDetailFeature/Demo/Sources/AppDelegate.swift
index ebbcf1b78..a349c0521 100644
--- a/Projects/Features/MusicDetailFeature/Demo/Sources/AppDelegate.swift
+++ b/Projects/Features/MusicDetailFeature/Demo/Sources/AppDelegate.swift
@@ -90,31 +90,31 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
}
}
-final class DummyLyricHighlightingFactory: LyricHighlightingFactory {
+final class DummyLyricHighlightingFactory: LyricHighlightingFactory, @unchecked Sendable {
func makeView(model: LyricHighlightingRequiredModel) -> UIViewController {
return UIViewController()
}
}
-final class DummyContainSongsFactory: ContainSongsFactory {
+final class DummyContainSongsFactory: ContainSongsFactory, @unchecked Sendable {
func makeView(songs: [String]) -> UIViewController {
return UIViewController()
}
}
-final class DummySongCreditFactory: SongCreditFactory {
+final class DummySongCreditFactory: SongCreditFactory, @unchecked Sendable {
func makeViewController(songID: String) -> UIViewController {
return UIViewController()
}
}
-final class DummySignInFactory: SignInFactory {
+final class DummySignInFactory: SignInFactory, @unchecked Sendable {
func makeView() -> UIViewController {
return UIViewController()
}
}
-final class DummyTextPopupFactory: TextPopupFactory {
+final class DummyTextPopupFactory: TextPopupFactory, @unchecked Sendable {
func makeView(
text: String?,
cancelButtonIsHidden: Bool,
@@ -127,19 +127,19 @@ final class DummyTextPopupFactory: TextPopupFactory {
}
}
-final class DummyPlaylistPresenterGlobalState: PlayListPresenterGlobalStateProtocol {
+final class DummyPlaylistPresenterGlobalState: PlayListPresenterGlobalStateProtocol, @unchecked Sendable {
var presentPlayListObservable: RxSwift.Observable { .empty() }
func presentPlayList(currentSongID: String?) {}
func presentPlayList() {}
}
-final class DummyKaraokeFactory: KaraokeFactory {
+final class DummyKaraokeFactory: KaraokeFactory, @unchecked Sendable {
func makeViewController(ky: Int?, tj: Int?) -> UIViewController {
UIViewController()
}
}
-final class DummyArtistDetailFactory: ArtistDetailFactory {
+final class DummyArtistDetailFactory: ArtistDetailFactory, @unchecked Sendable {
func makeView(artistID: String) -> UIViewController {
UIViewController()
}
diff --git a/Projects/Features/MusicDetailFeature/Interface/KaraokeFactory.swift b/Projects/Features/MusicDetailFeature/Interface/KaraokeFactory.swift
index 1ce7c0045..307978779 100644
--- a/Projects/Features/MusicDetailFeature/Interface/KaraokeFactory.swift
+++ b/Projects/Features/MusicDetailFeature/Interface/KaraokeFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol KaraokeFactory {
func makeViewController(ky: Int?, tj: Int?) -> UIViewController
}
diff --git a/Projects/Features/MusicDetailFeature/Interface/MusicDetailFactory.swift b/Projects/Features/MusicDetailFeature/Interface/MusicDetailFactory.swift
index fe384d845..147032f34 100644
--- a/Projects/Features/MusicDetailFeature/Interface/MusicDetailFactory.swift
+++ b/Projects/Features/MusicDetailFeature/Interface/MusicDetailFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol MusicDetailFactory {
func makeViewController(songIDs: [String], selectedID: String) -> UIViewController
}
diff --git a/Projects/Features/MusicDetailFeature/Sources/Karaoke/Views/KaraokeContentView.swift b/Projects/Features/MusicDetailFeature/Sources/Karaoke/Views/KaraokeContentView.swift
index 978d200e2..1535c26d6 100644
--- a/Projects/Features/MusicDetailFeature/Sources/Karaoke/Views/KaraokeContentView.swift
+++ b/Projects/Features/MusicDetailFeature/Sources/Karaoke/Views/KaraokeContentView.swift
@@ -3,6 +3,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
private protocol KaraokeContentStateProtocol {
func update(number: Int?, kind: KaraokeKind)
}
diff --git a/Projects/Features/MusicDetailFeature/Sources/Karaoke/Views/KaraokeInfoView.swift b/Projects/Features/MusicDetailFeature/Sources/Karaoke/Views/KaraokeInfoView.swift
index 370ab439a..f3f871fc3 100644
--- a/Projects/Features/MusicDetailFeature/Sources/Karaoke/Views/KaraokeInfoView.swift
+++ b/Projects/Features/MusicDetailFeature/Sources/Karaoke/Views/KaraokeInfoView.swift
@@ -3,6 +3,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
private protocol KaraokeStateProtocol {
func update(ky: Int?, tj: Int?)
}
diff --git a/Projects/Features/MusicDetailFeature/Sources/MusicDetail/MusicDetailReactor.swift b/Projects/Features/MusicDetailFeature/Sources/MusicDetail/MusicDetailReactor.swift
index 8b3f9bc6e..a52e00bea 100644
--- a/Projects/Features/MusicDetailFeature/Sources/MusicDetail/MusicDetailReactor.swift
+++ b/Projects/Features/MusicDetailFeature/Sources/MusicDetail/MusicDetailReactor.swift
@@ -355,7 +355,7 @@ private extension MusicDetailReactor {
}
func likeButtonDidTap() -> Observable {
- guard PreferenceManager.userInfo != nil else {
+ guard PreferenceManager.shared.userInfo != nil else {
return navigateMutation(
navigate: NavigateType.textPopup(
text: LocalizationStrings.needLoginWarning,
@@ -401,7 +401,7 @@ private extension MusicDetailReactor {
let log = CommonAnalyticsLog.clickAddMusicsButton(location: .songDetail)
LogManager.analytics(log)
- guard PreferenceManager.userInfo != nil else {
+ guard PreferenceManager.shared.userInfo != nil else {
return navigateMutation(
navigate: NavigateType.textPopup(
text: LocalizationStrings.needLoginWarning,
diff --git a/Projects/Features/MusicDetailFeature/Sources/MusicDetail/MusicDetailView.swift b/Projects/Features/MusicDetailFeature/Sources/MusicDetail/MusicDetailView.swift
index 1441a4af1..7c3f9e598 100644
--- a/Projects/Features/MusicDetailFeature/Sources/MusicDetail/MusicDetailView.swift
+++ b/Projects/Features/MusicDetailFeature/Sources/MusicDetail/MusicDetailView.swift
@@ -7,6 +7,7 @@ import Then
import UIKit
import Utility
+@MainActor
private protocol MusicDetailStateProtocol {
func updateTitle(title: String)
func updateArtist(artist: String)
@@ -246,14 +247,17 @@ extension MusicDetailView: MusicDetailStateProtocol {
}
}
-extension Reactive: MusicDetailActionProtocol where Base: MusicDetailView {
+extension Reactive: @preconcurrency MusicDetailActionProtocol where Base: MusicDetailView {
var prevMusicButtonDidTap: Observable { base.musicControlView.rx.prevMusicButtonDidTap }
var playMusicButtonDidTap: Observable { base.musicControlView.rx.playMusicButtonDidTap }
var nextMusicButtonDidTap: Observable { base.musicControlView.rx.nextMusicButtonDidTap }
var singingRoomButtonDidTap: Observable { base.musicControlView.rx.singingRoomButtonDidTap }
var lyricsButtonDidTap: Observable { base.musicControlView.rx.lyricsButtonDidTap }
+ @MainActor
var likeButtonDidTap: Observable { base.musicToolbarView.rx.likeButtonDidTap }
+ @MainActor
var musicPickButtonDidTap: Observable { base.musicToolbarView.rx.musicPickButtonDidTap }
+ @MainActor
var playlistButtonDidTap: Observable { base.musicToolbarView.rx.playlistButtonDidTap }
var creditButtonDidTap: Observable { base.creditButton.rx.tap.asObservable() }
var dismissButtonDidTap: Observable { base.dismissButton.rx.tap.asObservable() }
diff --git a/Projects/Features/MusicDetailFeature/Sources/MusicDetail/Views/MusicControlView/MusicControlView.swift b/Projects/Features/MusicDetailFeature/Sources/MusicDetail/Views/MusicControlView/MusicControlView.swift
index ff3789c61..7c4f441f4 100644
--- a/Projects/Features/MusicDetailFeature/Sources/MusicDetail/Views/MusicControlView/MusicControlView.swift
+++ b/Projects/Features/MusicDetailFeature/Sources/MusicDetail/Views/MusicControlView/MusicControlView.swift
@@ -7,6 +7,7 @@ import Then
import UIKit
import Utility
+@MainActor
private protocol MusicControlStateProtool {
func updateTitle(title: String)
func updateArtist(artist: String)
diff --git a/Projects/Features/MusicDetailFeature/Sources/MusicDetail/Views/MusicToolbarView.swift b/Projects/Features/MusicDetailFeature/Sources/MusicDetail/Views/MusicToolbarView.swift
index a7636ad4b..d2724b13d 100644
--- a/Projects/Features/MusicDetailFeature/Sources/MusicDetail/Views/MusicToolbarView.swift
+++ b/Projects/Features/MusicDetailFeature/Sources/MusicDetail/Views/MusicToolbarView.swift
@@ -5,6 +5,7 @@ import Then
import UIKit
import Utility
+@MainActor
private protocol MusicToolbarStateProtocol {
func updateViews(views: Int)
func updateIsLike(likes: Int, isLike: Bool)
@@ -70,15 +71,18 @@ extension MusicToolbarView: MusicToolbarStateProtocol {
}
}
-extension Reactive: MusicToolbarActionProtocol where Base: MusicToolbarView {
+extension Reactive: @preconcurrency MusicToolbarActionProtocol where Base: MusicToolbarView {
+ @MainActor
var likeButtonDidTap: Observable {
base.heartButton.rx.tap.asObservable()
}
+ @MainActor
var musicPickButtonDidTap: Observable {
base.musicPickButton.rx.tap.asObservable()
}
+ @MainActor
var playlistButtonDidTap: Observable {
base.playlistButton.rx.tap.asObservable()
}
diff --git a/Projects/Features/MyInfoFeature/Interface/Protocol/Factory.swift b/Projects/Features/MyInfoFeature/Interface/Protocol/Factory.swift
index 9b27cabab..afd281757 100644
--- a/Projects/Features/MyInfoFeature/Interface/Protocol/Factory.swift
+++ b/Projects/Features/MyInfoFeature/Interface/Protocol/Factory.swift
@@ -2,42 +2,52 @@ import FaqDomainInterface
import NoticeDomainInterface
import UIKit
+@MainActor
public protocol MyInfoFactory {
func makeView() -> UIViewController
}
+@MainActor
public protocol SettingFactory {
func makeView() -> UIViewController
}
+@MainActor
public protocol OpenSourceLicenseFactory {
func makeView() -> UIViewController
}
+@MainActor
public protocol FaqFactory {
func makeView() -> UIViewController
}
+@MainActor
public protocol FaqContentFactory {
func makeView(dataSource: [FaqEntity]) -> UIViewController
}
+@MainActor
public protocol NoticeFactory {
func makeView() -> UIViewController
}
+@MainActor
public protocol NoticeDetailFactory {
func makeView(model: FetchNoticeEntity) -> UIViewController
}
+@MainActor
public protocol QuestionFactory {
func makeView() -> UIViewController
}
+@MainActor
public protocol ServiceInfoFactory {
func makeView() -> UIViewController
}
+@MainActor
public protocol ProfilePopupFactory {
func makeView(completion: (() -> Void)?) -> UIViewController
}
diff --git a/Projects/Features/MyInfoFeature/Interface/Protocol/PlayTypeTogglePopupFactory.swift b/Projects/Features/MyInfoFeature/Interface/Protocol/PlayTypeTogglePopupFactory.swift
index 11ada2cbb..eee9fcfc3 100644
--- a/Projects/Features/MyInfoFeature/Interface/Protocol/PlayTypeTogglePopupFactory.swift
+++ b/Projects/Features/MyInfoFeature/Interface/Protocol/PlayTypeTogglePopupFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol PlayTypeTogglePopupFactory {
func makeView(
completion: ((_ selectedItemString: String) -> Void)?,
diff --git a/Projects/Features/MyInfoFeature/Sources/Reactors/MyInfoReactor.swift b/Projects/Features/MyInfoFeature/Sources/Reactors/MyInfoReactor.swift
index 06f465b98..bcba6cebb 100644
--- a/Projects/Features/MyInfoFeature/Sources/Reactors/MyInfoReactor.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Reactors/MyInfoReactor.swift
@@ -199,7 +199,7 @@ final class MyInfoReactor: Reactor {
private extension MyInfoReactor {
func viewDidLoad() -> Observable {
- guard PreferenceManager.userInfo != nil else { return .empty() }
+ guard PreferenceManager.shared.userInfo != nil else { return .empty() }
return mutateFetchUserInfo()
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Reactors/SettingReactor.swift b/Projects/Features/MyInfoFeature/Sources/Reactors/SettingReactor.swift
index 785ecf21b..225be12f6 100644
--- a/Projects/Features/MyInfoFeature/Sources/Reactors/SettingReactor.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Reactors/SettingReactor.swift
@@ -68,7 +68,6 @@ final class SettingReactor: Reactor {
private let withDrawUserInfoUseCase: any WithdrawUserInfoUseCase
private let logoutUseCase: any LogoutUseCase
private let updateNotificationTokenUseCase: any UpdateNotificationTokenUseCase
- private let naverLoginInstance = NaverThirdPartyLoginConnection.getSharedInstance()
init(
withDrawUserInfoUseCase: WithdrawUserInfoUseCase,
@@ -76,10 +75,10 @@ final class SettingReactor: Reactor {
updateNotificationTokenUseCase: UpdateNotificationTokenUseCase
) {
self.initialState = .init(
- userInfo: Utility.PreferenceManager.userInfo,
+ userInfo: Utility.PreferenceManager.shared.userInfo,
isHiddenLogoutButton: true,
isHiddenWithDrawButton: true,
- notificationAuthorizationStatus: PreferenceManager.pushNotificationAuthorizationStatus ?? false,
+ notificationAuthorizationStatus: PreferenceManager.shared.pushNotificationAuthorizationStatus ?? false,
isShowActivityIndicator: false
)
self.withDrawUserInfoUseCase = withDrawUserInfoUseCase
@@ -146,7 +145,7 @@ final class SettingReactor: Reactor {
}
func transform(mutation: Observable) -> Observable {
- let updateIsLoggedInMutation = PreferenceManager.$userInfo.map { $0?.ID }
+ let updateIsLoggedInMutation = PreferenceManager.shared.$userInfo.map { $0?.ID }
.distinctUntilChanged()
.map { $0 != nil }
.withUnretained(self)
@@ -157,7 +156,8 @@ final class SettingReactor: Reactor {
)
}
- let updatepushNotificationAuthorizationStatusMutation = PreferenceManager.$pushNotificationAuthorizationStatus
+ let updatepushNotificationAuthorizationStatusMutation = PreferenceManager.shared
+ .$pushNotificationAuthorizationStatus
.skip(1)
.distinctUntilChanged()
.map { $0 ?? false }
@@ -165,7 +165,7 @@ final class SettingReactor: Reactor {
return .just(.changedNotificationAuthorizationStatus(granted))
}
- let updatePlayTypeMutation = PreferenceManager.$songPlayPlatformType
+ let updatePlayTypeMutation = PreferenceManager.shared.$songPlayPlatformType
.distinctUntilChanged()
.map { $0 ?? .youtube }
.flatMap { playType -> Observable in
@@ -197,7 +197,7 @@ private extension SettingReactor {
}
func confirmLogoutButtonDidTap() -> Observable {
- let notificationGranted = PreferenceManager.pushNotificationAuthorizationStatus ?? false
+ let notificationGranted = PreferenceManager.shared.pushNotificationAuthorizationStatus ?? false
let logoutUseCase = logoutUseCase.execute(localOnly: false)
.andThen(
.concat(
@@ -328,9 +328,11 @@ private extension SettingReactor {
private extension SettingReactor {
func handleThirdPartyWithDraw() -> Observable {
- let platform = Utility.PreferenceManager.userInfo?.platform
+ let platform = Utility.PreferenceManager.shared.userInfo?.platform
if platform == "naver" {
- naverLoginInstance?.requestDeleteToken()
+ Task { @MainActor in
+ NaverThirdPartyLoginConnection.getSharedInstance().requestDeleteToken()
+ }
}
return .empty()
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Service/MyInfoCommonService.swift b/Projects/Features/MyInfoFeature/Sources/Service/MyInfoCommonService.swift
index bf251b766..a4651ac5a 100644
--- a/Projects/Features/MyInfoFeature/Sources/Service/MyInfoCommonService.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Service/MyInfoCommonService.swift
@@ -13,12 +13,12 @@ final class DefaultMyInfoCommonService: MyInfoCommonService {
let didChangedUserInfoEvent: Observable
let didChangedReadNoticeIDsEvent: Observable<[Int]?>
- static let shared = DefaultMyInfoCommonService()
+ nonisolated(unsafe) static let shared = DefaultMyInfoCommonService()
init() {
let notificationCenter = NotificationCenter.default
willRefreshUserInfoEvent = notificationCenter.rx.notification(.willRefreshUserInfo)
- didChangedUserInfoEvent = PreferenceManager.$userInfo
- didChangedReadNoticeIDsEvent = PreferenceManager.$readNoticeIDs
+ didChangedUserInfoEvent = PreferenceManager.shared.$userInfo
+ didChangedReadNoticeIDsEvent = PreferenceManager.shared.$readNoticeIDs
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/ViewControllers/FAQ/FaqViewController.swift b/Projects/Features/MyInfoFeature/Sources/ViewControllers/FAQ/FaqViewController.swift
index 6c395ef6a..74ffb3ad9 100644
--- a/Projects/Features/MyInfoFeature/Sources/ViewControllers/FAQ/FaqViewController.swift
+++ b/Projects/Features/MyInfoFeature/Sources/ViewControllers/FAQ/FaqViewController.swift
@@ -138,7 +138,7 @@ extension FaqViewController {
}
}
-extension FaqViewController: PageboyViewControllerDataSource, TMBarDataSource {
+extension FaqViewController: @preconcurrency PageboyViewControllerDataSource, @preconcurrency TMBarDataSource {
public func numberOfViewControllers(in pageboyViewController: Pageboy.PageboyViewController) -> Int {
LogManager.printDebug(self.viewControllers.count)
return self.viewControllers.count
diff --git a/Projects/Features/MyInfoFeature/Sources/ViewControllers/MyInfo/MyInfoViewController.swift b/Projects/Features/MyInfoFeature/Sources/ViewControllers/MyInfo/MyInfoViewController.swift
index 60cb00400..fdbd64cbd 100644
--- a/Projects/Features/MyInfoFeature/Sources/ViewControllers/MyInfo/MyInfoViewController.swift
+++ b/Projects/Features/MyInfoFeature/Sources/ViewControllers/MyInfo/MyInfoViewController.swift
@@ -14,7 +14,7 @@ import Then
import UIKit
import Utility
-final class MyInfoViewController: BaseReactorViewController, EditSheetViewType {
+final class MyInfoViewController: BaseReactorViewController, @preconcurrency EditSheetViewType {
let myInfoView = MyInfoView()
private var profilePopupFactory: ProfilePopupFactory!
private var textPopupFactory: TextPopupFactory!
@@ -339,16 +339,20 @@ extension MyInfoViewController: EditSheetViewDelegate {
}
extension MyInfoViewController: EqualHandleTappedType {
- func equalHandleTapped() {
- let viewControllersCount: Int = self.navigationController?.viewControllers.count ?? 0
- if viewControllersCount > 1 {
- self.navigationController?.popToRootViewController(animated: true)
+ nonisolated func equalHandleTapped() {
+ Task { @MainActor in
+ let viewControllersCount: Int = self.navigationController?.viewControllers.count ?? 0
+ if viewControllersCount > 1 {
+ self.navigationController?.popToRootViewController(animated: true)
+ }
}
}
}
extension MyInfoViewController: FruitDrawViewControllerDelegate {
- func completedFruitDraw(itemCount: Int) {
- reactor?.action.onNext(.completedFruitDraw)
+ nonisolated func completedFruitDraw(itemCount: Int) {
+ Task { @MainActor in
+ reactor?.action.onNext(.completedFruitDraw)
+ }
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/ViewControllers/OpenSourceLicense/OpenSourceLicenseViewController.swift b/Projects/Features/MyInfoFeature/Sources/ViewControllers/OpenSourceLicense/OpenSourceLicenseViewController.swift
index fc7a58cd5..a8964ea40 100644
--- a/Projects/Features/MyInfoFeature/Sources/ViewControllers/OpenSourceLicense/OpenSourceLicenseViewController.swift
+++ b/Projects/Features/MyInfoFeature/Sources/ViewControllers/OpenSourceLicense/OpenSourceLicenseViewController.swift
@@ -44,6 +44,8 @@ public class OpenSourceLicenseViewController: UIViewController, ViewControllerFr
extension OpenSourceLicenseViewController {
private func inputBind() {
+ viewModel.input.viewDidLoad.onNext(())
+
tableView.rx
.setDelegate(self)
.disposed(by: disposeBag)
diff --git a/Projects/Features/MyInfoFeature/Sources/ViewControllers/PlayTypeTogglePopup/PlayTypeTogglePopupViewController.swift b/Projects/Features/MyInfoFeature/Sources/ViewControllers/PlayTypeTogglePopup/PlayTypeTogglePopupViewController.swift
index 865c21107..98c8e5443 100644
--- a/Projects/Features/MyInfoFeature/Sources/ViewControllers/PlayTypeTogglePopup/PlayTypeTogglePopupViewController.swift
+++ b/Projects/Features/MyInfoFeature/Sources/ViewControllers/PlayTypeTogglePopup/PlayTypeTogglePopupViewController.swift
@@ -232,7 +232,7 @@ private extension PlayTypeTogglePopupViewController {
self.view.backgroundColor = .clear
contentView.clipsToBounds = true
- let playType = PreferenceManager.songPlayPlatformType ?? .youtube
+ let playType = PreferenceManager.shared.songPlayPlatformType ?? .youtube
self.selectedItemString = playType.display
firstItemButton.setTitleWithOption(title: YoutubePlayType.youtube.display)
diff --git a/Projects/Features/MyInfoFeature/Sources/ViewControllers/Question/QuestionViewController.swift b/Projects/Features/MyInfoFeature/Sources/ViewControllers/Question/QuestionViewController.swift
index b8a02d189..e036f739f 100644
--- a/Projects/Features/MyInfoFeature/Sources/ViewControllers/Question/QuestionViewController.swift
+++ b/Projects/Features/MyInfoFeature/Sources/ViewControllers/Question/QuestionViewController.swift
@@ -282,7 +282,7 @@ extension QuestionViewController {
}
}
-extension QuestionViewController: MFMailComposeViewControllerDelegate {
+extension QuestionViewController: @preconcurrency MFMailComposeViewControllerDelegate {
public func mailComposeController(
_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult,
diff --git a/Projects/Features/MyInfoFeature/Sources/ViewControllers/Setting/SettingViewController.swift b/Projects/Features/MyInfoFeature/Sources/ViewControllers/Setting/SettingViewController.swift
index 8b1583d9a..d8f619719 100644
--- a/Projects/Features/MyInfoFeature/Sources/ViewControllers/Setting/SettingViewController.swift
+++ b/Projects/Features/MyInfoFeature/Sources/ViewControllers/Setting/SettingViewController.swift
@@ -261,7 +261,7 @@ extension SettingViewController: UITableViewDelegate {
completion: { selectedItemString in
switch selectedItemString {
case YoutubePlayType.youtube.display:
- PreferenceManager.songPlayPlatformType = .youtube
+ PreferenceManager.shared.songPlayPlatformType = .youtube
LogManager.analytics(
SettingAnalyticsLog.completeSelectSongPlayPlatform(platform: YoutubePlayType.youtube.display)
)
@@ -269,7 +269,7 @@ extension SettingViewController: UITableViewDelegate {
property: .songPlayPlatform(platform: YoutubePlayType.youtube.display)
)
case YoutubePlayType.youtubeMusic.display:
- PreferenceManager.songPlayPlatformType = .youtubeMusic
+ PreferenceManager.shared.songPlayPlatformType = .youtubeMusic
LogManager.analytics(
SettingAnalyticsLog.completeSelectSongPlayPlatform(
platform: YoutubePlayType.youtubeMusic.display
diff --git a/Projects/Features/MyInfoFeature/Sources/ViewModels/NoticeDetailViewModel.swift b/Projects/Features/MyInfoFeature/Sources/ViewModels/NoticeDetailViewModel.swift
index c3bd4df47..fc54ffb46 100644
--- a/Projects/Features/MyInfoFeature/Sources/ViewModels/NoticeDetailViewModel.swift
+++ b/Projects/Features/MyInfoFeature/Sources/ViewModels/NoticeDetailViewModel.swift
@@ -65,12 +65,12 @@ public final class NoticeDetailViewModel {
private extension NoticeDetailViewModel {
func readNotice(ID: Int) {
- var newReadNoticeIDs = PreferenceManager.readNoticeIDs ?? []
+ var newReadNoticeIDs = PreferenceManager.shared.readNoticeIDs ?? []
guard newReadNoticeIDs.contains(ID) == false else {
return
}
newReadNoticeIDs.append(ID)
- PreferenceManager.readNoticeIDs = newReadNoticeIDs
+ PreferenceManager.shared.readNoticeIDs = newReadNoticeIDs
}
func downloadImageSize(url: URL) -> Observable {
diff --git a/Projects/Features/MyInfoFeature/Sources/ViewModels/NoticeViewModel.swift b/Projects/Features/MyInfoFeature/Sources/ViewModels/NoticeViewModel.swift
index 689269e4e..8d32c43f3 100644
--- a/Projects/Features/MyInfoFeature/Sources/ViewModels/NoticeViewModel.swift
+++ b/Projects/Features/MyInfoFeature/Sources/ViewModels/NoticeViewModel.swift
@@ -35,7 +35,7 @@ public final class NoticeViewModel {
.catchAndReturn([])
}
.map { notices in
- let readIDs = Set(PreferenceManager.readNoticeIDs ?? [])
+ let readIDs = Set(PreferenceManager.shared.readNoticeIDs ?? [])
return notices.map { notice in
var notice = notice
notice.isRead = readIDs.contains(notice.id)
diff --git a/Projects/Features/MyInfoFeature/Sources/ViewModels/OpenSourceLicenseViewModel.swift b/Projects/Features/MyInfoFeature/Sources/ViewModels/OpenSourceLicenseViewModel.swift
index a70d96583..811fe60dc 100644
--- a/Projects/Features/MyInfoFeature/Sources/ViewModels/OpenSourceLicenseViewModel.swift
+++ b/Projects/Features/MyInfoFeature/Sources/ViewModels/OpenSourceLicenseViewModel.swift
@@ -7,185 +7,179 @@
//
import Foundation
-import RxCocoa
-import RxSwift
+@preconcurrency import RxCocoa
+@preconcurrency import RxSwift
import Utility
-public final class OpenSourceLicenseViewModel {
+public final class OpenSourceLicenseViewModel: Sendable {
let input = Input()
let output = Output()
- var disposeBag = DisposeBag()
+ let disposeBag = DisposeBag()
- public struct Input {}
- public struct Output {
- var dataSource: BehaviorRelay<[OpenSourceLicense]> = BehaviorRelay(value: [])
+ public struct Input: Sendable {
+ let viewDidLoad: PublishSubject = PublishSubject()
}
- init() {
- var dataSource: [OpenSourceLicense] = [
- OpenSourceLicense(
- title: "Alamofire",
- description: "The MIT License\nCopyright (c) 2014-2018 Alamofire Software Foundation",
- link: "https://github.com/Alamofire/Alamofire"
- ),
- OpenSourceLicense(
- title: "Moya",
- description: "The MIT License\nCopyright (c) 2014-present Artsy, Ash Furrow",
- link: "https://github.com/Moya/Moya.git"
- ),
- OpenSourceLicense(
- title: "Kingfisher",
- description: "The MIT License\nCopyright (c) 2018 Wei Wang",
- link: "https://github.com/onevcat/Kingfisher.git"
- ),
- OpenSourceLicense(
- title: "RxSwift",
- description: "The MIT License\nCopyright ยฉ 2015 Krunoslav Zaher All rights reserved.",
- link: "https://github.com/ReactiveX/RxSwift.git"
- ),
- OpenSourceLicense(
- title: "RxGesture",
- description: "The MIT License\nCopyright ยฉ 2016 RxSwiftCommunity.",
- link: "https://github.com/RxSwiftCommunity/RxGesture.git"
- ),
- OpenSourceLicense(
- title: "RxDataSources",
- description: "The MIT License\nCopyright (c) 2017 RxSwift Community",
- link: "https://github.com/RxSwiftCommunity/RxDataSources.git"
- ),
- OpenSourceLicense(
- title: "RxKeyboard",
- description: "The MIT License\nCopyright (c) 2016 Suyeol Jeon (xoul.kr)",
- link: "https://github.com/RxSwiftCommunity/RxKeyboard.git"
- ),
- OpenSourceLicense(
- title: "FittedSheets",
- description: "The MIT License\nCopyright (c) 2018 Gordon Tucker",
- link: "https://github.com/gordontucker/FittedSheets.git"
- ),
- OpenSourceLicense(
- title: "Then",
- description: "The MIT License\nCopyright (c) 2015 Suyeol Jeon (xoul.kr)",
- link: "https://github.com/devxoul/Then"
- ),
- OpenSourceLicense(
- title: "SnapKit",
- description: "The MIT License\nCopyright (c) 2011-Present SnapKit Team",
- link: "https://github.com/SnapKit/SnapKit.git"
- ),
- OpenSourceLicense(
- title: "Reachability",
- description: "The MIT License\nCopyright (c) 2016 Ashley Mills",
- link: "https://github.com/ashleymills/Reachability.swift"
- ),
- OpenSourceLicense(
- title: "Lottie-ios",
- description: "Apache License 2.0\nCopyright 2018 Airbnb, Inc.",
- link: "https://github.com/airbnb/lottie-ios.git"
- ),
- OpenSourceLicense(
- title: "Needle",
- description: "uber/needle is licensed under the Apache License 2.0",
- link: "https://github.com/uber/needle.git"
- ),
- OpenSourceLicense(
- title: "Tabman",
- description: "The MIT License\nCopyright (c) 2022 UI At Six",
- link: "https://github.com/uias/Tabman.git"
- ),
- OpenSourceLicense(
- title: "SwiftEntryKit",
- description: "The MIT License\nCopyright (c) 2018 Daniel Huri",
- link: "https://github.com/huri000/SwiftEntryKit"
- ),
- OpenSourceLicense(
- title: "Naveridlogin-sdk-ios",
- description: "naver/naveridlogin-sdk-ios is licensed under the Apache License 2.0",
- link: "https://github.com/naver/naveridlogin-sdk-ios"
- ),
- OpenSourceLicense(
- title: "CryptoSwift",
- description: "The MIT License\nCopyright (C) 2014-3099 Marcin Krzyลผanowski",
- link: "https://github.com/krzyzanowskim/CryptoSwift.git"
- ),
- OpenSourceLicense(
- title: "MarqueeLabel",
- description: "The MIT License\nCopyright (c) 2011-2017 Charles Powell",
- link: "https://github.com/cbpowell/MarqueeLabel.git"
- ),
- OpenSourceLicense(
- title: "Firebase-ios-sdk",
- description: "firebase/firebase-ios-sdk is licensed under the Apache License 2.0",
- link: "https://github.com/firebase/firebase-ios-sdk.git"
- ),
- OpenSourceLicense(
- title: "NVActivityIndicatorView",
- description: "The MIT License\nCopyright (c) 2016 Vinh Nguyen",
- link: "https://github.com/ninjaprox/NVActivityIndicatorView.git"
- ),
- OpenSourceLicense(
- title: "RealmSwift",
- description: "realm/realm-swift is licensed under the Apache License 2.0",
- link: "https://github.com/realm/realm-swift"
- )
- ].sorted { $0.title < $1.title }
+ public struct Output: Sendable {
+ let dataSource: BehaviorRelay<[OpenSourceLicense]> = BehaviorRelay(value: [])
+ }
+
+ init() {}
+
+ func bind() {
+ input.viewDidLoad.bind { [weak self] in
+ self?.loadLicense()
+ }
+ .disposed(by: disposeBag)
+ }
+
+ private func loadLicense() {
+ Task {
+ var dataSource: [OpenSourceLicense] = [
+ OpenSourceLicense(
+ title: "Alamofire",
+ description: "The MIT License\nCopyright (c) 2014-2018 Alamofire Software Foundation",
+ link: "https://github.com/Alamofire/Alamofire"
+ ),
+ OpenSourceLicense(
+ title: "Moya",
+ description: "The MIT License\nCopyright (c) 2014-present Artsy, Ash Furrow",
+ link: "https://github.com/Moya/Moya.git"
+ ),
+ OpenSourceLicense(
+ title: "Kingfisher",
+ description: "The MIT License\nCopyright (c) 2018 Wei Wang",
+ link: "https://github.com/onevcat/Kingfisher.git"
+ ),
+ OpenSourceLicense(
+ title: "RxSwift",
+ description: "The MIT License\nCopyright ยฉ 2015 Krunoslav Zaher All rights reserved.",
+ link: "https://github.com/ReactiveX/RxSwift.git"
+ ),
+ OpenSourceLicense(
+ title: "RxGesture",
+ description: "The MIT License\nCopyright ยฉ 2016 RxSwiftCommunity.",
+ link: "https://github.com/RxSwiftCommunity/RxGesture.git"
+ ),
+ OpenSourceLicense(
+ title: "RxDataSources",
+ description: "The MIT License\nCopyright (c) 2017 RxSwift Community",
+ link: "https://github.com/RxSwiftCommunity/RxDataSources.git"
+ ),
+ OpenSourceLicense(
+ title: "RxKeyboard",
+ description: "The MIT License\nCopyright (c) 2016 Suyeol Jeon (xoul.kr)",
+ link: "https://github.com/RxSwiftCommunity/RxKeyboard.git"
+ ),
+ OpenSourceLicense(
+ title: "FittedSheets",
+ description: "The MIT License\nCopyright (c) 2018 Gordon Tucker",
+ link: "https://github.com/gordontucker/FittedSheets.git"
+ ),
+ OpenSourceLicense(
+ title: "Then",
+ description: "The MIT License\nCopyright (c) 2015 Suyeol Jeon (xoul.kr)",
+ link: "https://github.com/devxoul/Then"
+ ),
+ OpenSourceLicense(
+ title: "SnapKit",
+ description: "The MIT License\nCopyright (c) 2011-Present SnapKit Team",
+ link: "https://github.com/SnapKit/SnapKit.git"
+ ),
+ OpenSourceLicense(
+ title: "Reachability",
+ description: "The MIT License\nCopyright (c) 2016 Ashley Mills",
+ link: "https://github.com/ashleymills/Reachability.swift"
+ ),
+ OpenSourceLicense(
+ title: "Lottie-ios",
+ description: "Apache License 2.0\nCopyright 2018 Airbnb, Inc.",
+ link: "https://github.com/airbnb/lottie-ios.git"
+ ),
+ OpenSourceLicense(
+ title: "Needle",
+ description: "uber/needle is licensed under the Apache License 2.0",
+ link: "https://github.com/uber/needle.git"
+ ),
+ OpenSourceLicense(
+ title: "Tabman",
+ description: "The MIT License\nCopyright (c) 2022 UI At Six",
+ link: "https://github.com/uias/Tabman.git"
+ ),
+ OpenSourceLicense(
+ title: "SwiftEntryKit",
+ description: "The MIT License\nCopyright (c) 2018 Daniel Huri",
+ link: "https://github.com/huri000/SwiftEntryKit"
+ ),
+ OpenSourceLicense(
+ title: "Naveridlogin-sdk-ios",
+ description: "naver/naveridlogin-sdk-ios is licensed under the Apache License 2.0",
+ link: "https://github.com/naver/naveridlogin-sdk-ios"
+ ),
+ OpenSourceLicense(
+ title: "CryptoSwift",
+ description: "The MIT License\nCopyright (C) 2014-3099 Marcin Krzyลผanowski",
+ link: "https://github.com/krzyzanowskim/CryptoSwift.git"
+ ),
+ OpenSourceLicense(
+ title: "MarqueeLabel",
+ description: "The MIT License\nCopyright (c) 2011-2017 Charles Powell",
+ link: "https://github.com/cbpowell/MarqueeLabel.git"
+ ),
+ OpenSourceLicense(
+ title: "Firebase-ios-sdk",
+ description: "firebase/firebase-ios-sdk is licensed under the Apache License 2.0",
+ link: "https://github.com/firebase/firebase-ios-sdk.git"
+ ),
+ OpenSourceLicense(
+ title: "NVActivityIndicatorView",
+ description: "The MIT License\nCopyright (c) 2016 Vinh Nguyen",
+ link: "https://github.com/ninjaprox/NVActivityIndicatorView.git"
+ ),
+ OpenSourceLicense(
+ title: "RealmSwift",
+ description: "realm/realm-swift is licensed under the Apache License 2.0",
+ link: "https://github.com/realm/realm-swift"
+ )
+ ].sorted { $0.title < $1.title }
- self.loadTextFileFromBundle(fileName: "ApacheLicense") { [weak self] result in
- guard let self else { return }
- switch result {
- case let .success(contents):
- let apacheLicense = OpenSourceLicense(
+ async let apacheLicenseContent = loadTextFileFromBundle(fileName: "ApacheLicense")
+ async let mitLicenseContent = loadTextFileFromBundle(fileName: "MITLicense")
+
+ let (
+ apacheLicense,
+ mitLicense
+ ) = try await (
+ OpenSourceLicense(
type: .license,
title: "Apache License 2.0",
- description: contents,
+ description: apacheLicenseContent,
+ link: ""
+ ),
+ OpenSourceLicense(
+ type: .license,
+ title: "MIT License (MIT)",
+ description: mitLicenseContent,
link: ""
)
- dataSource.append(apacheLicense)
-
- self.loadTextFileFromBundle(fileName: "MITLicense") { [weak self] result in
- guard let self else { return }
- switch result {
- case let .success(contents):
- let mitLicense = OpenSourceLicense(
- type: .license,
- title: "MIT License (MIT)",
- description: contents,
- link: ""
- )
- dataSource.append(mitLicense)
- self.output.dataSource.accept(dataSource)
+ )
- case let .failure(error):
- DEBUG_LOG("ํ์ผ ๋ก๋ ์๋ฌ: \(error)")
- }
- }
- case let .failure(error):
- DEBUG_LOG("ํ์ผ ๋ก๋ ์๋ฌ: \(error)")
- }
+ dataSource.append(apacheLicense)
+ dataSource.append(mitLicense)
+ self.output.dataSource.accept(dataSource)
}
- }
-}
-extension OpenSourceLicenseViewModel {
- private func loadTextFileFromBundle(
- fileName: String,
- completionHandler: @escaping (Result) -> Void
- ) {
- DispatchQueue.global().async {
+ func loadTextFileFromBundle(fileName: String) async throws -> String {
if let fileURL = MyInfoFeatureResources.bundle.url(forResource: fileName, withExtension: "txt") {
- do {
- let contents = try String(contentsOf: fileURL, encoding: .utf8)
- completionHandler(.success(contents))
- } catch {
- completionHandler(.failure(error))
- }
+ let contents = try String(contentsOf: fileURL, encoding: .utf8)
+ return contents
} else {
let error = NSError(
- domain: "com.example.app",
+ domain: "yongbeomkwak.Billboardoo",
code: 0,
userInfo: [NSLocalizedDescriptionKey: "ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค."]
)
- completionHandler(.failure(error))
+ throw error
}
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/ViewModels/QuestionViewModel.swift b/Projects/Features/MyInfoFeature/Sources/ViewModels/QuestionViewModel.swift
index 8ed3fff35..56cd6c584 100644
--- a/Projects/Features/MyInfoFeature/Sources/ViewModels/QuestionViewModel.swift
+++ b/Projects/Features/MyInfoFeature/Sources/ViewModels/QuestionViewModel.swift
@@ -127,6 +127,7 @@ extension InquiryType {
}
}
+ @MainActor
var suffix: String {
switch self {
default:
@@ -135,7 +136,7 @@ extension InquiryType {
* ์๋์ผ๋ก ์์ฑ๋ ์์คํ
์ ๋ณด์
๋๋ค. ์ํํ ๋ฌธ์๋ฅผ ์ํด์ ์ญ์ ํ์ง ๋ง์ ์ฃผ์ธ์.\n
\(APP_NAME()) v\(APP_VERSION())
\(Device().modelName) / \(OS_NAME()) \(OS_VERSION())
- ๋๋ค์: \(Utility.PreferenceManager.userInfo?.decryptedName ?? "")
+ ๋๋ค์: \(Utility.PreferenceManager.shared.userInfo?.decryptedName ?? "")
"""
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/AnswerTableViewCell.swift b/Projects/Features/MyInfoFeature/Sources/Views/AnswerTableViewCell.swift
index 20392cb6b..b34bf264d 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/AnswerTableViewCell.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/AnswerTableViewCell.swift
@@ -7,8 +7,10 @@ class AnswerTableViewCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- answerLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 14)
- answerLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 6)
+ Task { @MainActor in
+ answerLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 14)
+ answerLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 6)
+ }
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/FruitDrawButtonView.swift b/Projects/Features/MyInfoFeature/Sources/Views/FruitDrawButtonView.swift
index 83002867f..42f57aae5 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/FruitDrawButtonView.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/FruitDrawButtonView.swift
@@ -5,6 +5,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
private protocol FruitDrawStateProtocol {
func updateFruitCount(count: Int)
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/MyInfoView.swift b/Projects/Features/MyInfoFeature/Sources/Views/MyInfoView.swift
index 894c8874d..128abc0b1 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/MyInfoView.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/MyInfoView.swift
@@ -8,6 +8,7 @@ import UIKit
import UserDomainInterface
import Utility
+@MainActor
private protocol MyInfoStateProtocol {
func updateIsHiddenLoginWarningView(isLoggedIn: Bool)
func updateFruitCount(count: Int)
@@ -30,6 +31,7 @@ private protocol MyInfoActionProtocol {
final class MyInfoView: UIView {
let scrollView = UIScrollView()
let contentView = UIView()
+ fileprivate let tapGestureRecognizer = UITapGestureRecognizer()
let loginWarningView = LoginWarningView(text: "๋ก๊ทธ์ธ์ ํด์ฃผ์ธ์.")
@@ -90,6 +92,8 @@ final class MyInfoView: UIView {
super.init(frame: .zero)
addView()
setLayout()
+ scrollView.addGestureRecognizer(tapGestureRecognizer)
+ scrollView.isUserInteractionEnabled = true
self.backgroundColor = DesignSystemAsset.BlueGrayColor.blueGray100.color
}
@@ -195,15 +199,13 @@ extension MyInfoView: MyInfoStateProtocol {
}
}
-extension Reactive: MyInfoActionProtocol where Base: MyInfoView {
+extension Reactive: @preconcurrency MyInfoActionProtocol where Base: MyInfoView {
var scrollViewDidTap: Observable {
- let tapGestureRecognizer = UITapGestureRecognizer()
- base.scrollView.addGestureRecognizer(tapGestureRecognizer)
- base.scrollView.isUserInteractionEnabled = true
- return tapGestureRecognizer.rx.event.map { _ in }.asObservable()
+ return base.tapGestureRecognizer.rx.event.map { _ in }.asObservable()
}
var loginButtonDidTap: Observable { base.loginWarningView.rx.loginButtonDidTap }
+ @MainActor
var profileImageDidTap: Observable { base.profileView.rx.profileImageDidTap }
var fruitStorageButtonDidTap: Observable { base.fruitDrawButtonView.rx.fruitStorageButtonDidTap }
var drawButtonDidTap: Observable { base.fruitDrawButtonView.rx.drawButtonDidTap }
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/NoticeDetailHeaderView.swift b/Projects/Features/MyInfoFeature/Sources/Views/NoticeDetailHeaderView.swift
index a9fd653d9..3b533180c 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/NoticeDetailHeaderView.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/NoticeDetailHeaderView.swift
@@ -12,21 +12,23 @@ class NoticeDetailHeaderView: UICollectionReusableView {
override func awakeFromNib() {
super.awakeFromNib()
- titleStringLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 18)
- titleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
- titleStringLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 1.26)
+ Task { @MainActor in
+ titleStringLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 18)
+ titleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
+ titleStringLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 1.26)
- dateLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
- dateLabel.textColor = DesignSystemAsset.BlueGrayColor.gray500.color
- dateLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 0)
+ dateLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
+ dateLabel.textColor = DesignSystemAsset.BlueGrayColor.gray500.color
+ dateLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 0)
- timeLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
- timeLabel.textColor = DesignSystemAsset.BlueGrayColor.gray500.color
- timeLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 0)
+ timeLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
+ timeLabel.textColor = DesignSystemAsset.BlueGrayColor.gray500.color
+ timeLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 0)
- contentStringLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 14)
- contentStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
- contentStringLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 1.26)
+ contentStringLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 14)
+ contentStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
+ contentStringLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 1.26)
+ }
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/NoticeListCell.swift b/Projects/Features/MyInfoFeature/Sources/Views/NoticeListCell.swift
index 719cf798b..7491dd960 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/NoticeListCell.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/NoticeListCell.swift
@@ -10,20 +10,22 @@ class NoticeListCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- self.backgroundColor = .clear
- self.contentView.backgroundColor = .clear
+ Task { @MainActor in
+ self.backgroundColor = .clear
+ self.contentView.backgroundColor = .clear
- titleStringLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 16)
- titleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.blueGray900.color
- titleStringLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 1.26)
+ titleStringLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 16)
+ titleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.blueGray900.color
+ titleStringLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 1.26)
- dayLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
- dayLabel.textColor = DesignSystemAsset.BlueGrayColor.blueGray500.color
- dayLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 0)
+ dayLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
+ dayLabel.textColor = DesignSystemAsset.BlueGrayColor.blueGray500.color
+ dayLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 0)
- timeLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
- timeLabel.textColor = DesignSystemAsset.BlueGrayColor.blueGray500.color
- timeLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 0)
+ timeLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
+ timeLabel.textColor = DesignSystemAsset.BlueGrayColor.blueGray500.color
+ timeLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 0, lineHeightMultiple: 0)
+ }
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/OpenSourceLibraryCell.swift b/Projects/Features/MyInfoFeature/Sources/Views/OpenSourceLibraryCell.swift
index 70187daf1..25eb8b90c 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/OpenSourceLibraryCell.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/OpenSourceLibraryCell.swift
@@ -16,17 +16,19 @@ public class OpenSourceLibraryCell: UITableViewCell {
override public func awakeFromNib() {
super.awakeFromNib()
- self.backgroundColor = .clear
- self.contentView.backgroundColor = .clear
- titleStringLabel.font = DesignSystemFontFamily.Pretendard.bold.font(size: 15)
- titleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
- titleStringLabel.setTextWithAttributes(kernValue: -0.5)
- titleStringLabel.numberOfLines = 0
- descriptionLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 13)
- descriptionLabel.textColor = DesignSystemAsset.BlueGrayColor.gray500.color
- descriptionLabel.setTextWithAttributes(kernValue: -0.5)
- descriptionLabel.lineBreakMode = .byWordWrapping
- descriptionLabel.numberOfLines = 0
+ Task { @MainActor in
+ self.backgroundColor = .clear
+ self.contentView.backgroundColor = .clear
+ titleStringLabel.font = DesignSystemFontFamily.Pretendard.bold.font(size: 15)
+ titleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
+ titleStringLabel.setTextWithAttributes(kernValue: -0.5)
+ titleStringLabel.numberOfLines = 0
+ descriptionLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 13)
+ descriptionLabel.textColor = DesignSystemAsset.BlueGrayColor.gray500.color
+ descriptionLabel.setTextWithAttributes(kernValue: -0.5)
+ descriptionLabel.lineBreakMode = .byWordWrapping
+ descriptionLabel.numberOfLines = 0
+ }
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/OpenSourceLicenseCell.swift b/Projects/Features/MyInfoFeature/Sources/Views/OpenSourceLicenseCell.swift
index d1f15254b..bef5d51d4 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/OpenSourceLicenseCell.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/OpenSourceLicenseCell.swift
@@ -16,17 +16,19 @@ class OpenSourceLicenseCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- self.backgroundColor = .clear
- self.contentView.backgroundColor = .clear
- titleStringLabel.font = DesignSystemFontFamily.Pretendard.bold.font(size: 18)
- titleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
- titleStringLabel.setTextWithAttributes(kernValue: -0.5)
- titleStringLabel.numberOfLines = 0
- descriptionLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 13)
- descriptionLabel.textColor = DesignSystemAsset.BlueGrayColor.gray500.color
- descriptionLabel.setTextWithAttributes(kernValue: -0.5)
- descriptionLabel.lineBreakMode = .byWordWrapping
- descriptionLabel.numberOfLines = 0
+ Task { @MainActor in
+ self.backgroundColor = .clear
+ self.contentView.backgroundColor = .clear
+ titleStringLabel.font = DesignSystemFontFamily.Pretendard.bold.font(size: 18)
+ titleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
+ titleStringLabel.setTextWithAttributes(kernValue: -0.5)
+ titleStringLabel.numberOfLines = 0
+ descriptionLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 13)
+ descriptionLabel.textColor = DesignSystemAsset.BlueGrayColor.gray500.color
+ descriptionLabel.setTextWithAttributes(kernValue: -0.5)
+ descriptionLabel.lineBreakMode = .byWordWrapping
+ descriptionLabel.numberOfLines = 0
+ }
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/PlayTypeTogglePopupItemButton.swift b/Projects/Features/MyInfoFeature/Sources/Views/PlayTypeTogglePopupItemButton.swift
index 02423ee13..706799cbd 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/PlayTypeTogglePopupItemButton.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/PlayTypeTogglePopupItemButton.swift
@@ -3,6 +3,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
protocol PlayTypeTogglePopupItemButtonViewDelegate: AnyObject {
func tappedButtonAction(title: String)
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/ProfileCollectionViewCell.swift b/Projects/Features/MyInfoFeature/Sources/Views/ProfileCollectionViewCell.swift
index 121019677..e14514623 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/ProfileCollectionViewCell.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/ProfileCollectionViewCell.swift
@@ -9,8 +9,10 @@ public class ProfileCollectionViewCell: UICollectionViewCell {
override public func awakeFromNib() {
super.awakeFromNib()
- clipsToBounds = false
- contentView.clipsToBounds = false
+ Task { @MainActor in
+ clipsToBounds = false
+ contentView.clipsToBounds = false
+ }
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/ProfileView.swift b/Projects/Features/MyInfoFeature/Sources/Views/ProfileView.swift
index 8a27a11af..aa3b1e593 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/ProfileView.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/ProfileView.swift
@@ -8,6 +8,7 @@ import Then
import UIKit
import Utility
+@MainActor
private protocol ProfileStateProtocol {
func updateProfileImage(image: String)
func updateNickName(nickname: String)
@@ -170,7 +171,8 @@ extension ProfileView: ProfileStateProtocol {
}
}
-extension Reactive: ProfileActionProtocol where Base: ProfileView {
+extension Reactive: @preconcurrency ProfileActionProtocol where Base: ProfileView {
+ @MainActor
var profileImageDidTap: Observable {
return base.didTapProfileImageSubject.asObserver()
.throttle(.milliseconds(500), latest: false, scheduler: MainScheduler.asyncInstance)
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/QuestionTableViewCell.swift b/Projects/Features/MyInfoFeature/Sources/Views/QuestionTableViewCell.swift
index ce19cce34..55535f824 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/QuestionTableViewCell.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/QuestionTableViewCell.swift
@@ -9,10 +9,12 @@ class QuestionTableViewCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- categoryLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
- categoryLabel.setTextWithAttributes(kernValue: -0.5)
- titleLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 16)
- titleLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 5)
+ Task { @MainActor in
+ categoryLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
+ categoryLabel.setTextWithAttributes(kernValue: -0.5)
+ titleLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 16)
+ titleLabel.setTextWithAttributes(kernValue: -0.5, lineSpacing: 5)
+ }
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/ServiceInfoCell.swift b/Projects/Features/MyInfoFeature/Sources/Views/ServiceInfoCell.swift
index 241988d67..ada2fdc06 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/ServiceInfoCell.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/ServiceInfoCell.swift
@@ -18,15 +18,17 @@ class ServiceInfoCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- arrowImageView.image = DesignSystemAsset.Navigation.serviceInfoArrowRight.image
- self.backgroundColor = .clear
- self.contentView.backgroundColor = .clear
- titleStringLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 16)
- titleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
- titleStringLabel.setTextWithAttributes(kernValue: -0.5)
- subTitleStringLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
- subTitleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray500.color
- subTitleStringLabel.setTextWithAttributes(kernValue: -0.5)
+ Task { @MainActor in
+ arrowImageView.image = DesignSystemAsset.Navigation.serviceInfoArrowRight.image
+ self.backgroundColor = .clear
+ self.contentView.backgroundColor = .clear
+ titleStringLabel.font = DesignSystemFontFamily.Pretendard.medium.font(size: 16)
+ titleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray900.color
+ titleStringLabel.setTextWithAttributes(kernValue: -0.5)
+ subTitleStringLabel.font = DesignSystemFontFamily.Pretendard.light.font(size: 12)
+ subTitleStringLabel.textColor = DesignSystemAsset.BlueGrayColor.gray500.color
+ subTitleStringLabel.setTextWithAttributes(kernValue: -0.5)
+ }
}
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/SettingItemTableViewCell.swift b/Projects/Features/MyInfoFeature/Sources/Views/SettingItemTableViewCell.swift
index d35b6a63b..47f91230d 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/SettingItemTableViewCell.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/SettingItemTableViewCell.swift
@@ -71,8 +71,9 @@ private extension SettingItemTableViewCell {
func configureSubTitle(type: SettingItemType) {
switch type {
case let .navigate(category):
- let pushNotificationAuthorizationStatus = PreferenceManager.pushNotificationAuthorizationStatus ?? false
- let playType = PreferenceManager.songPlayPlatformType ?? .youtube
+ let pushNotificationAuthorizationStatus = PreferenceManager.shared
+ .pushNotificationAuthorizationStatus ?? false
+ let playType = PreferenceManager.shared.songPlayPlatformType ?? .youtube
switch category {
case .appPush:
self.subTitleLabel.text = pushNotificationAuthorizationStatus ? "์ผ์ง" : "๊บผ์ง"
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/SettingView.swift b/Projects/Features/MyInfoFeature/Sources/Views/SettingView.swift
index 59ae8108c..2c37d005e 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/SettingView.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/SettingView.swift
@@ -9,6 +9,7 @@ import UIKit
import UserDomainInterface
import Utility
+@MainActor
private protocol SettingStateProtocol {
func updateIsHiddenWithDrawButton(isHidden: Bool)
func updateIsHiddenLogoutButton(isHidden: Bool)
@@ -152,7 +153,8 @@ extension SettingView: SettingStateProtocol {
}
}
-extension Reactive: SettingActionProtocol where Base: SettingView {
+extension Reactive: @preconcurrency SettingActionProtocol where Base: SettingView {
+ @MainActor
var withDrawButtonDidTap: Observable { base.withDrawLabel.rx.didTap }
var dismissButtonDidTap: Observable { base.dismissButton.rx.tap.asObservable() }
}
diff --git a/Projects/Features/MyInfoFeature/Sources/Views/WithDrawLabel.swift b/Projects/Features/MyInfoFeature/Sources/Views/WithDrawLabel.swift
index 1f07a648b..e72efe56e 100644
--- a/Projects/Features/MyInfoFeature/Sources/Views/WithDrawLabel.swift
+++ b/Projects/Features/MyInfoFeature/Sources/Views/WithDrawLabel.swift
@@ -74,6 +74,7 @@ final class WithDrawLabel: UILabel {
}
extension Reactive where Base: WithDrawLabel {
+ @MainActor
var didTap: Observable {
return base.didTapSubject.asObservable()
}
diff --git a/Projects/Features/MyInfoFeature/Testing/FaqComponentStub.swift b/Projects/Features/MyInfoFeature/Testing/FaqComponentStub.swift
index caa833a07..d41edc124 100644
--- a/Projects/Features/MyInfoFeature/Testing/FaqComponentStub.swift
+++ b/Projects/Features/MyInfoFeature/Testing/FaqComponentStub.swift
@@ -5,7 +5,7 @@ import Foundation
import MyInfoFeatureInterface
import UIKit
-public final class FaqComponentStub: FaqFactory {
+public final class FaqComponentStub: FaqFactory, @unchecked Sendable {
public func makeView() -> UIViewController {
return FaqViewController.viewController(
viewModel: .init(
diff --git a/Projects/Features/MyInfoFeature/Testing/FaqContentComponentStub.swift b/Projects/Features/MyInfoFeature/Testing/FaqContentComponentStub.swift
index 9b1ec61e7..f43708149 100644
--- a/Projects/Features/MyInfoFeature/Testing/FaqContentComponentStub.swift
+++ b/Projects/Features/MyInfoFeature/Testing/FaqContentComponentStub.swift
@@ -4,7 +4,7 @@ import Foundation
import MyInfoFeatureInterface
import UIKit
-public final class FaqContentComponentStub: FaqContentFactory {
+public final class FaqContentComponentStub: FaqContentFactory, @unchecked Sendable {
public func makeView(dataSource: [FaqEntity]) -> UIViewController {
return FaqContentViewController.viewController(viewModel: .init(dataSource: dataSource))
}
diff --git a/Projects/Features/MyInfoFeature/Testing/MyInfoComponentStub.swift b/Projects/Features/MyInfoFeature/Testing/MyInfoComponentStub.swift
index a58859682..f07388835 100644
--- a/Projects/Features/MyInfoFeature/Testing/MyInfoComponentStub.swift
+++ b/Projects/Features/MyInfoFeature/Testing/MyInfoComponentStub.swift
@@ -6,7 +6,7 @@ import SignInFeatureInterface
@testable import SignInFeatureTesting
import UIKit
-public final class MyInfoComponentStub: MyInfoFactory {
+public final class MyInfoComponentStub: MyInfoFactory, @unchecked Sendable {
public func makeView() -> UIViewController {
return UIViewController()
}
diff --git a/Projects/Features/MyInfoFeature/Testing/NoticeComponentStub.swift b/Projects/Features/MyInfoFeature/Testing/NoticeComponentStub.swift
index 8ce8e626f..92bdf2ab9 100644
--- a/Projects/Features/MyInfoFeature/Testing/NoticeComponentStub.swift
+++ b/Projects/Features/MyInfoFeature/Testing/NoticeComponentStub.swift
@@ -6,7 +6,7 @@ import NoticeDomainInterface
@testable import NoticeDomainTesting
import UIKit
-public final class NoticeComponentStub: NoticeFactory {
+public final class NoticeComponentStub: NoticeFactory, @unchecked Sendable {
public func makeView() -> UIViewController {
return NoticeViewController.viewController(
viewModel: .init(
diff --git a/Projects/Features/MyInfoFeature/Testing/NoticeDetailComponentStub.swift b/Projects/Features/MyInfoFeature/Testing/NoticeDetailComponentStub.swift
index a549b6196..e30b244a0 100644
--- a/Projects/Features/MyInfoFeature/Testing/NoticeDetailComponentStub.swift
+++ b/Projects/Features/MyInfoFeature/Testing/NoticeDetailComponentStub.swift
@@ -4,7 +4,7 @@ import MyInfoFeatureInterface
import NoticeDomainInterface
import UIKit
-public final class NoticeDetailComponentStub: NoticeDetailFactory {
+public final class NoticeDetailComponentStub: NoticeDetailFactory, @unchecked Sendable {
public func makeView(model: FetchNoticeEntity) -> UIViewController {
return NoticeDetailViewController.viewController(
viewModel: .init(
diff --git a/Projects/Features/MyInfoFeature/Testing/OpenSourceLicenseComponentStub.swift b/Projects/Features/MyInfoFeature/Testing/OpenSourceLicenseComponentStub.swift
index 6f9d484b9..9694a60eb 100644
--- a/Projects/Features/MyInfoFeature/Testing/OpenSourceLicenseComponentStub.swift
+++ b/Projects/Features/MyInfoFeature/Testing/OpenSourceLicenseComponentStub.swift
@@ -3,7 +3,7 @@ import Foundation
import MyInfoFeatureInterface
import UIKit
-public final class OpenSourceLicenseComponentStub: OpenSourceLicenseFactory {
+public final class OpenSourceLicenseComponentStub: OpenSourceLicenseFactory, @unchecked Sendable {
public func makeView() -> UIViewController {
return OpenSourceLicenseViewController.viewController(
viewModel: OpenSourceLicenseViewModel()
diff --git a/Projects/Features/MyInfoFeature/Testing/QuestionComponentStub.swift b/Projects/Features/MyInfoFeature/Testing/QuestionComponentStub.swift
index 808b849d2..bb9062dac 100644
--- a/Projects/Features/MyInfoFeature/Testing/QuestionComponentStub.swift
+++ b/Projects/Features/MyInfoFeature/Testing/QuestionComponentStub.swift
@@ -4,7 +4,7 @@ import BaseFeatureInterface
import MyInfoFeatureInterface
import UIKit
-public final class QuestionComponentStub: QuestionFactory {
+public final class QuestionComponentStub: QuestionFactory, @unchecked Sendable {
public func makeView() -> UIViewController {
return QuestionViewController.viewController(
viewModel: .init(),
diff --git a/Projects/Features/MyInfoFeature/Testing/SettingComponentStub.swift b/Projects/Features/MyInfoFeature/Testing/SettingComponentStub.swift
index ea6cd31d8..9db711481 100644
--- a/Projects/Features/MyInfoFeature/Testing/SettingComponentStub.swift
+++ b/Projects/Features/MyInfoFeature/Testing/SettingComponentStub.swift
@@ -11,7 +11,7 @@ import UIKit
import UserDomainInterface
@testable import UserDomainTesting
-public final class SettingComponentStub: SettingFactory {
+public final class SettingComponentStub: SettingFactory, @unchecked Sendable {
public func makeView() -> UIViewController {
return SettingViewController.viewController(
reactor: SettingReactor(
@@ -29,7 +29,7 @@ public final class SettingComponentStub: SettingFactory {
}
}
-final class PlayTypeTogglePopupComponentStub: PlayTypeTogglePopupFactory {
+final class PlayTypeTogglePopupComponentStub: PlayTypeTogglePopupFactory, @unchecked Sendable {
public func makeView(
completion: ((_ selectedItemString: String) -> Void)? = nil,
cancelCompletion: (() -> Void)? = nil
diff --git a/Projects/Features/PlaylistFeature/Interface/CheckThumbnailFactory.swift b/Projects/Features/PlaylistFeature/Interface/CheckThumbnailFactory.swift
index f25461848..8cd9fd2fc 100644
--- a/Projects/Features/PlaylistFeature/Interface/CheckThumbnailFactory.swift
+++ b/Projects/Features/PlaylistFeature/Interface/CheckThumbnailFactory.swift
@@ -4,6 +4,7 @@ public protocol CheckPlaylistCoverDelegate: AnyObject {
func receive(_ imageData: Data)
}
+@MainActor
public protocol CheckPlaylistCoverFactory {
func makeView(delegate: any CheckPlaylistCoverDelegate, imageData: Data) -> UIViewController
}
diff --git a/Projects/Features/PlaylistFeature/Interface/DefaultPlaylistImageFactory.swift b/Projects/Features/PlaylistFeature/Interface/DefaultPlaylistImageFactory.swift
index c4b38e682..90694bff1 100644
--- a/Projects/Features/PlaylistFeature/Interface/DefaultPlaylistImageFactory.swift
+++ b/Projects/Features/PlaylistFeature/Interface/DefaultPlaylistImageFactory.swift
@@ -4,6 +4,7 @@ public protocol DefaultPlaylistCoverDelegate: AnyObject {
func receive(url: String, imageName: String)
}
+@MainActor
public protocol DefaultPlaylistCoverFactory {
func makeView(_ delegate: any DefaultPlaylistCoverDelegate) -> UIViewController
}
diff --git a/Projects/Features/PlaylistFeature/Interface/MyPlaylistDetailFactory.swift b/Projects/Features/PlaylistFeature/Interface/MyPlaylistDetailFactory.swift
index 27478f33a..96f63b023 100644
--- a/Projects/Features/PlaylistFeature/Interface/MyPlaylistDetailFactory.swift
+++ b/Projects/Features/PlaylistFeature/Interface/MyPlaylistDetailFactory.swift
@@ -1,6 +1,7 @@
import BaseFeatureInterface
import UIKit
+@MainActor
public protocol MyPlaylistDetailFactory {
func makeView(key: String) -> UIViewController
}
diff --git a/Projects/Features/PlaylistFeature/Interface/PlaylistCoverOptionPopupFactory.swift b/Projects/Features/PlaylistFeature/Interface/PlaylistCoverOptionPopupFactory.swift
index 71ee1f231..e0e66be2d 100644
--- a/Projects/Features/PlaylistFeature/Interface/PlaylistCoverOptionPopupFactory.swift
+++ b/Projects/Features/PlaylistFeature/Interface/PlaylistCoverOptionPopupFactory.swift
@@ -1,9 +1,11 @@
import UIKit
+@MainActor
public protocol PlaylistCoverOptionPopupDelegate: AnyObject {
func didTap(_ index: Int, _ price: Int)
}
+@MainActor
public protocol PlaylistCoverOptionPopupFactory {
func makeView(delegate: any PlaylistCoverOptionPopupDelegate) -> UIViewController
}
diff --git a/Projects/Features/PlaylistFeature/Interface/PlaylistDetailFactory.swift b/Projects/Features/PlaylistFeature/Interface/PlaylistDetailFactory.swift
index 0eb7e4541..4ac90222c 100644
--- a/Projects/Features/PlaylistFeature/Interface/PlaylistDetailFactory.swift
+++ b/Projects/Features/PlaylistFeature/Interface/PlaylistDetailFactory.swift
@@ -1,12 +1,13 @@
import BaseFeatureInterface
import UIKit
-public enum PlaylistDetailKind {
+public enum PlaylistDetailKind: Sendable {
case wakmu
case my
case unknown
}
+@MainActor
public protocol PlaylistDetailFactory {
func makeView(key: String) -> UIViewController
func makeWmView(key: String) -> UIViewController
diff --git a/Projects/Features/PlaylistFeature/Interface/PlaylistDetailNavigator.swift b/Projects/Features/PlaylistFeature/Interface/PlaylistDetailNavigator.swift
index 6e50ad01e..221ddcd81 100644
--- a/Projects/Features/PlaylistFeature/Interface/PlaylistDetailNavigator.swift
+++ b/Projects/Features/PlaylistFeature/Interface/PlaylistDetailNavigator.swift
@@ -1,6 +1,7 @@
import Foundation
import UIKit
+@MainActor
public protocol PlaylistDetailNavigator {
var playlistDetailFactory: any PlaylistDetailFactory { get }
@@ -10,12 +11,14 @@ public protocol PlaylistDetailNavigator {
}
public extension PlaylistDetailNavigator where Self: UIViewController {
+ @MainActor
func navigateWMPlaylistDetail(key: String) {
let dest = playlistDetailFactory.makeWmView(key: key)
self.navigationController?.pushViewController(dest, animated: true)
}
+ @MainActor
func navigatePlaylistDetail(key: String) {
let dest = playlistDetailFactory.makeView(key: key)
diff --git a/Projects/Features/PlaylistFeature/Interface/PlaylistFactory.swift b/Projects/Features/PlaylistFeature/Interface/PlaylistFactory.swift
index d6f220472..bdadb2c70 100644
--- a/Projects/Features/PlaylistFeature/Interface/PlaylistFactory.swift
+++ b/Projects/Features/PlaylistFeature/Interface/PlaylistFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol PlaylistFactory {
func makeViewController() -> UIViewController
func makeViewController(currentSongID: String) -> UIViewController
diff --git a/Projects/Features/PlaylistFeature/Interface/UnknownPlaylistDetailFactory.swift b/Projects/Features/PlaylistFeature/Interface/UnknownPlaylistDetailFactory.swift
index b47d91a29..ba6ff5e07 100644
--- a/Projects/Features/PlaylistFeature/Interface/UnknownPlaylistDetailFactory.swift
+++ b/Projects/Features/PlaylistFeature/Interface/UnknownPlaylistDetailFactory.swift
@@ -1,6 +1,7 @@
import BaseFeatureInterface
import UIKit
+@MainActor
public protocol UnknownPlaylistDetailFactory {
func makeView(key: String) -> UIViewController
}
diff --git a/Projects/Features/PlaylistFeature/Interface/WakmusicPlaylistDetailFactory.swift b/Projects/Features/PlaylistFeature/Interface/WakmusicPlaylistDetailFactory.swift
index 671ac6e51..80d332acd 100644
--- a/Projects/Features/PlaylistFeature/Interface/WakmusicPlaylistDetailFactory.swift
+++ b/Projects/Features/PlaylistFeature/Interface/WakmusicPlaylistDetailFactory.swift
@@ -1,6 +1,7 @@
import BaseFeatureInterface
import UIKit
+@MainActor
public protocol WakmusicPlaylistDetailFactory {
func makeView(key: String) -> UIViewController
}
diff --git a/Projects/Features/PlaylistFeature/Sources/DataSource/UnkwonPlaylistDetailDataSource.swift b/Projects/Features/PlaylistFeature/Sources/DataSource/UnkwonPlaylistDetailDataSource.swift
index b8fda3c41..310e0d849 100644
--- a/Projects/Features/PlaylistFeature/Sources/DataSource/UnkwonPlaylistDetailDataSource.swift
+++ b/Projects/Features/PlaylistFeature/Sources/DataSource/UnkwonPlaylistDetailDataSource.swift
@@ -1,4 +1,4 @@
-import SongsDomainInterface
+@preconcurrency import SongsDomainInterface
import UIKit
final class UnknownPlaylistDetailDataSource: UITableViewDiffableDataSource {
diff --git a/Projects/Features/PlaylistFeature/Sources/Reactors/UnknownPlaylistDetailReactor.swift b/Projects/Features/PlaylistFeature/Sources/Reactors/UnknownPlaylistDetailReactor.swift
index 82e552dc4..dbfa0140f 100644
--- a/Projects/Features/PlaylistFeature/Sources/Reactors/UnknownPlaylistDetailReactor.swift
+++ b/Projects/Features/PlaylistFeature/Sources/Reactors/UnknownPlaylistDetailReactor.swift
@@ -185,7 +185,7 @@ private extension UnknownPlaylistDetailReactor {
Observable.just(
Mutation.updateDataSource(Array(songs))
),
- PreferenceManager.userInfo == nil ? .just(.updateSubscribeState(false)) : owner
+ PreferenceManager.shared.userInfo == nil ? .just(.updateSubscribeState(false)) : owner
.checkSubscription()
])
}
@@ -271,7 +271,7 @@ private extension UnknownPlaylistDetailReactor {
let prev = currentState.isSubscribing
- if PreferenceManager.userInfo == nil {
+ if PreferenceManager.shared.userInfo == nil {
return .just(.updateLoginPopupState((true, .playlistSubscribe)))
} else {
return subscribePlaylistUseCase.execute(key: key, isSubscribing: prev)
diff --git a/Projects/Features/PlaylistFeature/Sources/Service/PlaylistCommonService.swift b/Projects/Features/PlaylistFeature/Sources/Service/PlaylistCommonService.swift
index c712251dc..f75b8d27b 100644
--- a/Projects/Features/PlaylistFeature/Sources/Service/PlaylistCommonService.swift
+++ b/Projects/Features/PlaylistFeature/Sources/Service/PlaylistCommonService.swift
@@ -1,12 +1,12 @@
import Foundation
-import RxSwift
+@preconcurrency import RxSwift
import Utility
protocol PlaylistCommonService {
var removeSubscriptionPlaylistEvent: Observable { get }
}
-final class DefaultPlaylistCommonService: PlaylistCommonService {
+final class DefaultPlaylistCommonService: PlaylistCommonService, Sendable {
let removeSubscriptionPlaylistEvent: Observable = NotificationCenter.default.rx
.notification(.didRemovedSubscriptionPlaylist)
diff --git a/Projects/Features/PlaylistFeature/Sources/ViewControllers/MyPlaylistDetailViewController.swift b/Projects/Features/PlaylistFeature/Sources/ViewControllers/MyPlaylistDetailViewController.swift
index 01573ccab..b1461f749 100644
--- a/Projects/Features/PlaylistFeature/Sources/ViewControllers/MyPlaylistDetailViewController.swift
+++ b/Projects/Features/PlaylistFeature/Sources/ViewControllers/MyPlaylistDetailViewController.swift
@@ -14,7 +14,8 @@ import UIKit
import Utility
final class MyPlaylistDetailViewController: BaseReactorViewController,
- PlaylistEditSheetViewType, SongCartViewType {
+ @preconcurrency PlaylistEditSheetViewType,
+ @preconcurrency SongCartViewType {
private enum Limit {
static let imageSizeLimitPerMB: Double = 10.0
}
@@ -698,19 +699,21 @@ extension MyPlaylistDetailViewController: PlaylistEditSheetDelegate {
}
extension MyPlaylistDetailViewController: RequestPermissionable {
- public func showPhotoLibrary() {
- var configuration = PHPickerConfiguration()
- configuration.filter = .any(of: [.images])
- configuration.selectionLimit = 1 // ๊ฐฏ์ ์ ํ
+ public nonisolated func showPhotoLibrary() {
+ Task { @MainActor in
+ var configuration = PHPickerConfiguration()
+ configuration.filter = .any(of: [.images])
+ configuration.selectionLimit = 1 // ๊ฐฏ์ ์ ํ
- let picker = PHPickerViewController(configuration: configuration)
- picker.delegate = self
+ let picker = PHPickerViewController(configuration: configuration)
+ picker.delegate = self
- let pickerToWrapNavigationController = picker.wrapNavigationController
- pickerToWrapNavigationController.modalPresentationStyle = .overFullScreen
- pickerToWrapNavigationController.setNavigationBarHidden(true, animated: false)
+ let pickerToWrapNavigationController = picker.wrapNavigationController
+ pickerToWrapNavigationController.modalPresentationStyle = .overFullScreen
+ pickerToWrapNavigationController.setNavigationBarHidden(true, animated: false)
- self.present(pickerToWrapNavigationController, animated: true)
+ self.present(pickerToWrapNavigationController, animated: true)
+ }
}
}
@@ -732,19 +735,19 @@ extension MyPlaylistDetailViewController: PHPickerViewControllerDelegate {
DEBUG_LOG("error: \(error)")
} else {
- DispatchQueue.main.async {
- guard let image = image as? UIImage,
- let resizeImage = image.customizeForPlaylistCover(
- targetSize: CGSize(width: 500, height: 500)
- ),
- var imageData = resizeImage.jpegData(compressionQuality: 1.0)
- else { return } // 80% ์์ถ
-
- let sizeMB: Double = Double(imageData.count).megabytes
-
- if sizeMB > Limit.imageSizeLimitPerMB {
- imageData = image.jpegData(compressionQuality: 0.8) ?? imageData
- }
+ guard let image = image as? UIImage,
+ let resizeImage = image.customizeForPlaylistCover(
+ targetSize: CGSize(width: 500, height: 500)
+ ),
+ var imageData = resizeImage.jpegData(compressionQuality: 1.0)
+ else { return } // 80% ์์ถ
+
+ let sizeMB: Double = Double(imageData.count).megabytes
+
+ if sizeMB > Limit.imageSizeLimitPerMB {
+ imageData = image.jpegData(compressionQuality: 0.8) ?? imageData
+ }
+ Task { @MainActor in
self.navigateToCheckPlaylistCover(imageData: imageData)
}
}
@@ -774,7 +777,7 @@ extension MyPlaylistDetailViewController: PlaylistCoverOptionPopupDelegate {
PlaylistAnalyticsLog.clickPlaylistImageButton(type: "custom")
)
- guard let user = PreferenceManager.userInfo else {
+ guard let user = PreferenceManager.shared.userInfo else {
return
}
@@ -790,15 +793,19 @@ extension MyPlaylistDetailViewController: PlaylistCoverOptionPopupDelegate {
}
extension MyPlaylistDetailViewController: CheckPlaylistCoverDelegate {
- func receive(_ imageData: Data) {
- reactor?.action.onNext(.changeImageData(.custom(data: imageData)))
- headerView.updateThumbnailFromGallery(imageData)
+ nonisolated func receive(_ imageData: Data) {
+ Task { @MainActor in
+ reactor?.action.onNext(.changeImageData(.custom(data: imageData)))
+ headerView.updateThumbnailFromGallery(imageData)
+ }
}
}
extension MyPlaylistDetailViewController: DefaultPlaylistCoverDelegate {
- func receive(url: String, imageName: String) {
- reactor?.action.onNext(.changeImageData(.default(imageName: imageName)))
- headerView.updateThumbnailByDefault(url)
+ nonisolated func receive(url: String, imageName: String) {
+ Task { @MainActor in
+ reactor?.action.onNext(.changeImageData(.default(imageName: imageName)))
+ headerView.updateThumbnailByDefault(url)
+ }
}
}
diff --git a/Projects/Features/PlaylistFeature/Sources/ViewControllers/PlaylistDetailContainerViewController.swift b/Projects/Features/PlaylistFeature/Sources/ViewControllers/PlaylistDetailContainerViewController.swift
index adb200e4e..8cd909d33 100644
--- a/Projects/Features/PlaylistFeature/Sources/ViewControllers/PlaylistDetailContainerViewController.swift
+++ b/Projects/Features/PlaylistFeature/Sources/ViewControllers/PlaylistDetailContainerViewController.swift
@@ -9,7 +9,7 @@ import UIKit
import Utility
final class PlaylistDetailContainerViewController: BaseReactorViewController,
- ContainerViewType {
+ @preconcurrency ContainerViewType {
var contentView: UIView! = UIView().then {
$0.backgroundColor = DesignSystemAsset.BlueGrayColor.gray100.color
}
@@ -74,7 +74,7 @@ final class PlaylistDetailContainerViewController: BaseReactorViewController,
- SongCartViewType {
+ @preconcurrency SongCartViewType {
var songCartView: SongCartView!
var bottomSheetView: BottomSheetView!
@@ -422,7 +422,7 @@ extension UnknownPlaylistDetailViewController: SongCartViewDelegate {
let log = CommonAnalyticsLog.clickAddMusicsButton(location: .playlistDetail)
LogManager.analytics(log)
- if PreferenceManager.userInfo == nil {
+ if PreferenceManager.shared.userInfo == nil {
reactor.action.onNext(.requestLoginRequiredAction(source: .addMusics))
return
}
diff --git a/Projects/Features/PlaylistFeature/Sources/ViewControllers/WakmusicPlaylistDetailViewController.swift b/Projects/Features/PlaylistFeature/Sources/ViewControllers/WakmusicPlaylistDetailViewController.swift
index 649588138..1ddf002fb 100644
--- a/Projects/Features/PlaylistFeature/Sources/ViewControllers/WakmusicPlaylistDetailViewController.swift
+++ b/Projects/Features/PlaylistFeature/Sources/ViewControllers/WakmusicPlaylistDetailViewController.swift
@@ -7,13 +7,13 @@ import PhotosUI
import ReactorKit
import SignInFeatureInterface
import SnapKit
-import SongsDomainInterface
+@preconcurrency import SongsDomainInterface
import Then
import UIKit
import Utility
final class WakmusicPlaylistDetailViewController: BaseReactorViewController,
- SongCartViewType {
+ @preconcurrency SongCartViewType {
var songCartView: SongCartView!
var bottomSheetView: BottomSheetView!
@@ -367,7 +367,7 @@ extension WakmusicPlaylistDetailViewController: SongCartViewDelegate {
return
}
- if PreferenceManager.userInfo == nil {
+ if PreferenceManager.shared.userInfo == nil {
reactor.action.onNext(.requestLoginRequiredAction)
return
}
diff --git a/Projects/Features/PlaylistFeature/Sources/Views/MyPlaylistHeaderView.swift b/Projects/Features/PlaylistFeature/Sources/Views/MyPlaylistHeaderView.swift
index 8b3a73cf5..b6fb17c8e 100644
--- a/Projects/Features/PlaylistFeature/Sources/Views/MyPlaylistHeaderView.swift
+++ b/Projects/Features/PlaylistFeature/Sources/Views/MyPlaylistHeaderView.swift
@@ -6,6 +6,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
private protocol MyPlaylistHeaderStateProtocol {
func updateEditState(_ isEditing: Bool)
func updateData(_ model: PlaylistDetailHeaderModel)
diff --git a/Projects/Features/PlaylistFeature/Sources/Views/PlaylistDateTableViewCell.swift b/Projects/Features/PlaylistFeature/Sources/Views/PlaylistDateTableViewCell.swift
index 89412273d..b4a9423f4 100644
--- a/Projects/Features/PlaylistFeature/Sources/Views/PlaylistDateTableViewCell.swift
+++ b/Projects/Features/PlaylistFeature/Sources/Views/PlaylistDateTableViewCell.swift
@@ -7,6 +7,7 @@ import Then
import UIKit
import Utility
+@MainActor
internal protocol PlaylistDateTableViewCellDelegate: AnyObject {
func thumbnailDidTap(key: String)
}
diff --git a/Projects/Features/PlaylistFeature/Sources/Views/PlaylistTableViewCell.swift b/Projects/Features/PlaylistFeature/Sources/Views/PlaylistTableViewCell.swift
index c45f85336..7e840f665 100644
--- a/Projects/Features/PlaylistFeature/Sources/Views/PlaylistTableViewCell.swift
+++ b/Projects/Features/PlaylistFeature/Sources/Views/PlaylistTableViewCell.swift
@@ -9,6 +9,7 @@ import Then
import UIKit
import Utility
+@MainActor
internal protocol PlaylistTableViewCellDelegate: AnyObject {
func playButtonDidTap(model: PlaylistItemModel)
}
diff --git a/Projects/Features/PlaylistFeature/Sources/Views/UnknownPlaylistHeaderView.swift b/Projects/Features/PlaylistFeature/Sources/Views/UnknownPlaylistHeaderView.swift
index d1d1eb8db..a29f72ec5 100644
--- a/Projects/Features/PlaylistFeature/Sources/Views/UnknownPlaylistHeaderView.swift
+++ b/Projects/Features/PlaylistFeature/Sources/Views/UnknownPlaylistHeaderView.swift
@@ -6,6 +6,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
private protocol UnknownPlaylistHeaderStateProtocol {
func updateData(_ model: PlaylistDetailHeaderModel)
}
diff --git a/Projects/Features/PlaylistFeature/Sources/Views/WakmusicPlaylistHeaderView.swift b/Projects/Features/PlaylistFeature/Sources/Views/WakmusicPlaylistHeaderView.swift
index 1b0ac6feb..16fc30bff 100644
--- a/Projects/Features/PlaylistFeature/Sources/Views/WakmusicPlaylistHeaderView.swift
+++ b/Projects/Features/PlaylistFeature/Sources/Views/WakmusicPlaylistHeaderView.swift
@@ -6,6 +6,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
private protocol WakmusicPlaylistHeaderStateProtocol {
func updateData(_ model: PlaylistDetailHeaderModel)
}
diff --git a/Projects/Features/PlaylistFeature/Testing/PlaylistDetailFactoryStub.swift b/Projects/Features/PlaylistFeature/Testing/PlaylistDetailFactoryStub.swift
index 6c46eb06d..d303f3aa1 100644
--- a/Projects/Features/PlaylistFeature/Testing/PlaylistDetailFactoryStub.swift
+++ b/Projects/Features/PlaylistFeature/Testing/PlaylistDetailFactoryStub.swift
@@ -1,7 +1,7 @@
import PlaylistFeatureInterface
import UIKit
-public final class PlaylistDetailFactoryStub: PlaylistDetailFactory {
+public final class PlaylistDetailFactoryStub: PlaylistDetailFactory, @unchecked Sendable {
public func makeView(key: String) -> UIViewController {
return UIViewController()
}
diff --git a/Projects/Features/RootFeature/Sources/Components/PermissionComponent.swift b/Projects/Features/RootFeature/Sources/Components/PermissionComponent.swift
index a1f6fe60e..d9538a614 100644
--- a/Projects/Features/RootFeature/Sources/Components/PermissionComponent.swift
+++ b/Projects/Features/RootFeature/Sources/Components/PermissionComponent.swift
@@ -11,6 +11,7 @@ import UIKit
public protocol PermissionDependency: Dependency {}
+@MainActor
public final class PermissionComponent: Component {
public func makeView() -> PermissionViewController {
return PermissionViewController.viewController()
diff --git a/Projects/Features/RootFeature/Sources/Components/RootComponent.swift b/Projects/Features/RootFeature/Sources/Components/RootComponent.swift
index f53e81416..d39b1276a 100644
--- a/Projects/Features/RootFeature/Sources/Components/RootComponent.swift
+++ b/Projects/Features/RootFeature/Sources/Components/RootComponent.swift
@@ -16,6 +16,7 @@ public protocol RootDependency: Dependency {
var textPopupFactory: any TextPopupFactory { get }
}
+@MainActor
public final class RootComponent: Component {
public func makeView() -> IntroViewController {
return IntroViewController.viewController(
diff --git a/Projects/Features/RootFeature/Sources/ViewControllers/PermissionViewController.swift b/Projects/Features/RootFeature/Sources/ViewControllers/PermissionViewController.swift
index 97cd991e8..b87bf9066 100644
--- a/Projects/Features/RootFeature/Sources/ViewControllers/PermissionViewController.swift
+++ b/Projects/Features/RootFeature/Sources/ViewControllers/PermissionViewController.swift
@@ -46,7 +46,7 @@ public class PermissionViewController: UIViewController, ViewControllerFromStory
@IBAction func confirmButtonAction(_ sender: Any) {
dismiss(animated: true, completion: {
- Utility.PreferenceManager.appPermissionChecked = true
+ Utility.PreferenceManager.shared.appPermissionChecked = true
})
}
}
diff --git a/Projects/Features/RootFeature/Sources/ViewModels/IntroViewModel.swift b/Projects/Features/RootFeature/Sources/ViewModels/IntroViewModel.swift
index cc66b2dbe..65894192a 100644
--- a/Projects/Features/RootFeature/Sources/ViewModels/IntroViewModel.swift
+++ b/Projects/Features/RootFeature/Sources/ViewModels/IntroViewModel.swift
@@ -54,7 +54,7 @@ public final class IntroViewModel: ViewModelType {
Observable.combineLatest(
input.fetchPermissionCheck,
- Utility.PreferenceManager.$appPermissionChecked
+ Utility.PreferenceManager.shared.$appPermissionChecked
) { _, permission -> Bool? in
return permission
}
@@ -97,7 +97,7 @@ public final class IntroViewModel: ViewModelType {
.disposed(by: disposeBag)
input.checkUserInfoPreference
- .withLatestFrom(PreferenceManager.$userInfo)
+ .withLatestFrom(PreferenceManager.shared.$userInfo)
.flatMap { [logoutUseCase, checkIsExistAccessTokenUseCase] userInfo -> Observable in
// ๋น๋ก๊ทธ์ธ ์ํ์ธ๋ฐ, ํค์ฒด์ธ์ ์ ์ฅ๋ ์์ธ์ค ํ ํฐ์ด ์ด์์๋ค๋๊ฑด ๋ก๊ทธ์ธ ์ํ๋ก ์ฑ์ ์ญ์ ํ ์ ์ ์
guard userInfo == nil else {
diff --git a/Projects/Features/SearchFeature/Interface/Factory/ListSearchResultFactory.swift b/Projects/Features/SearchFeature/Interface/Factory/ListSearchResultFactory.swift
index d37dfa03d..5464c312f 100644
--- a/Projects/Features/SearchFeature/Interface/Factory/ListSearchResultFactory.swift
+++ b/Projects/Features/SearchFeature/Interface/Factory/ListSearchResultFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol ListSearchResultFactory {
func makeView(_ text: String) -> UIViewController
}
diff --git a/Projects/Features/SearchFeature/Interface/Factory/SearchFactory.swift b/Projects/Features/SearchFeature/Interface/Factory/SearchFactory.swift
index 880e54544..96ec425d3 100644
--- a/Projects/Features/SearchFeature/Interface/Factory/SearchFactory.swift
+++ b/Projects/Features/SearchFeature/Interface/Factory/SearchFactory.swift
@@ -1,6 +1,7 @@
import BaseFeatureInterface
import UIKit
+@MainActor
public protocol SearchFactory {
func makeView() -> UIViewController
}
diff --git a/Projects/Features/SearchFeature/Interface/Factory/SongSearchResultFactory.swift b/Projects/Features/SearchFeature/Interface/Factory/SongSearchResultFactory.swift
index a309e21db..38f99c184 100644
--- a/Projects/Features/SearchFeature/Interface/Factory/SongSearchResultFactory.swift
+++ b/Projects/Features/SearchFeature/Interface/Factory/SongSearchResultFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol SongSearchResultFactory {
func makeView(_ text: String) -> UIViewController
}
diff --git a/Projects/Features/SearchFeature/Sources/After/Components/AfterSearchComponent.swift b/Projects/Features/SearchFeature/Sources/After/Components/AfterSearchComponent.swift
index 0fafabecd..782fb5fd9 100644
--- a/Projects/Features/SearchFeature/Sources/After/Components/AfterSearchComponent.swift
+++ b/Projects/Features/SearchFeature/Sources/After/Components/AfterSearchComponent.swift
@@ -11,6 +11,7 @@ public protocol AfterSearchDependency: Dependency {
var searchGlobalScrollState: any SearchGlobalScrollProtocol { get }
}
+@MainActor
public final class AfterSearchComponent: Component {
public func makeView(text: String) -> AfterSearchViewController {
return AfterSearchViewController.viewController(
diff --git a/Projects/Features/SearchFeature/Sources/After/Components/SearchOptionComponent.swift b/Projects/Features/SearchFeature/Sources/After/Components/SearchOptionComponent.swift
index 830c99eb0..95e91542e 100644
--- a/Projects/Features/SearchFeature/Sources/After/Components/SearchOptionComponent.swift
+++ b/Projects/Features/SearchFeature/Sources/After/Components/SearchOptionComponent.swift
@@ -3,6 +3,7 @@ import NeedleFoundation
import SearchDomainInterface
import UIKit
+@MainActor
public final class SearchOptionComponent: Component {
public func makeView(_ sortType: SortType) -> UIViewController {
return SearchSortOptionViewController(selectedModel: sortType)
diff --git a/Projects/Features/SearchFeature/Sources/After/Components/SearchSortOptionComponent.swift b/Projects/Features/SearchFeature/Sources/After/Components/SearchSortOptionComponent.swift
index 5a039ba75..62e854127 100644
--- a/Projects/Features/SearchFeature/Sources/After/Components/SearchSortOptionComponent.swift
+++ b/Projects/Features/SearchFeature/Sources/After/Components/SearchSortOptionComponent.swift
@@ -2,6 +2,7 @@ import NeedleFoundation
import SearchDomainInterface
import UIKit
+@MainActor
public final class SearchSortOptionComponent: Component {
public func makeView(_ selectedModel: SortType) -> UIViewController {
return SearchSortOptionViewController(selectedModel: selectedModel)
diff --git a/Projects/Features/SearchFeature/Sources/After/View/OptionButton.swift b/Projects/Features/SearchFeature/Sources/After/View/OptionButton.swift
index ec6ea7fde..48bf5e564 100644
--- a/Projects/Features/SearchFeature/Sources/After/View/OptionButton.swift
+++ b/Projects/Features/SearchFeature/Sources/After/View/OptionButton.swift
@@ -6,6 +6,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
private protocol OptionButtonStateProtocol {
func updateSortrState(_ filterType: SortType)
}
diff --git a/Projects/Features/SearchFeature/Sources/After/View/SearchOptionHeaderView.swift b/Projects/Features/SearchFeature/Sources/After/View/SearchOptionHeaderView.swift
index 5dcf98ad5..59a164ee8 100644
--- a/Projects/Features/SearchFeature/Sources/After/View/SearchOptionHeaderView.swift
+++ b/Projects/Features/SearchFeature/Sources/After/View/SearchOptionHeaderView.swift
@@ -6,6 +6,7 @@ import Then
import UIKit
import Utility
+@MainActor
private protocol SearchOptionHeaderStateProtocol {
func updateSortState(_ sortType: SortType)
}
@@ -133,7 +134,8 @@ extension SearchOptionHeaderView: SearchOptionHeaderStateProtocol {
}
}
-extension Reactive: SearchOptionHeaderActionProtocol where Base: SearchOptionHeaderView {
+extension Reactive: @preconcurrency SearchOptionHeaderActionProtocol where Base: SearchOptionHeaderView {
+ @MainActor
var selectedFilterItem: Observable {
base.collectionView.rx.itemSelected
.map { base.dataSource[$0.row] }
diff --git a/Projects/Features/SearchFeature/Sources/After/View/SongResultCell.swift b/Projects/Features/SearchFeature/Sources/After/View/SongResultCell.swift
index c89ea9d82..62ead6c1e 100644
--- a/Projects/Features/SearchFeature/Sources/After/View/SongResultCell.swift
+++ b/Projects/Features/SearchFeature/Sources/After/View/SongResultCell.swift
@@ -5,6 +5,7 @@ import SongsDomainInterface
import UIKit
import Utility
+@MainActor
public protocol SongResultCellDelegate: AnyObject {
func thumbnailDidTap(key: String)
}
diff --git a/Projects/Features/SearchFeature/Sources/After/ViewControllers/AfterSearchViewController.swift b/Projects/Features/SearchFeature/Sources/After/ViewControllers/AfterSearchViewController.swift
index e7ea91d74..af2ef6d3a 100644
--- a/Projects/Features/SearchFeature/Sources/After/ViewControllers/AfterSearchViewController.swift
+++ b/Projects/Features/SearchFeature/Sources/After/ViewControllers/AfterSearchViewController.swift
@@ -12,7 +12,8 @@ import Tabman
import UIKit
import Utility
-public final class AfterSearchViewController: TabmanViewController, ViewControllerFromStoryBoard, StoryboardView {
+public final class AfterSearchViewController: TabmanViewController, ViewControllerFromStoryBoard,
+ @preconcurrency StoryboardView {
@IBOutlet weak var tabBarView: UIView!
@IBOutlet weak var fakeView: UIView!
@IBOutlet weak var indicator: NVActivityIndicatorView!
@@ -122,7 +123,7 @@ extension AfterSearchViewController {
}
}
-extension AfterSearchViewController: PageboyViewControllerDataSource, TMBarDataSource {
+extension AfterSearchViewController: @preconcurrency PageboyViewControllerDataSource, @preconcurrency TMBarDataSource {
public func numberOfViewControllers(in pageboyViewController: Pageboy.PageboyViewController) -> Int {
2
}
diff --git a/Projects/Features/SearchFeature/Sources/After/ViewControllers/ListSearchResultViewController.swift b/Projects/Features/SearchFeature/Sources/After/ViewControllers/ListSearchResultViewController.swift
index 42c4e97c1..269a84482 100644
--- a/Projects/Features/SearchFeature/Sources/After/ViewControllers/ListSearchResultViewController.swift
+++ b/Projects/Features/SearchFeature/Sources/After/ViewControllers/ListSearchResultViewController.swift
@@ -217,10 +217,12 @@ extension ListSearchResultViewController {
}
extension ListSearchResultViewController: SearchSortOptionDelegate {
- func updateSortType(_ type: SortType) {
- LogManager.analytics(SearchAnalyticsLog.selectSearchSort(option: type.rawValue, category: "list"))
- if reactor?.currentState.sortType != type {
- reactor?.action.onNext(.changeSortType(type))
+ nonisolated func updateSortType(_ type: SortType) {
+ Task { @MainActor in
+ LogManager.analytics(SearchAnalyticsLog.selectSearchSort(option: type.rawValue, category: "list"))
+ if reactor?.currentState.sortType != type {
+ reactor?.action.onNext(.changeSortType(type))
+ }
}
}
}
diff --git a/Projects/Features/SearchFeature/Sources/After/ViewControllers/SongSearchResultViewController.swift b/Projects/Features/SearchFeature/Sources/After/ViewControllers/SongSearchResultViewController.swift
index 1f5ebe891..567c18b83 100644
--- a/Projects/Features/SearchFeature/Sources/After/ViewControllers/SongSearchResultViewController.swift
+++ b/Projects/Features/SearchFeature/Sources/After/ViewControllers/SongSearchResultViewController.swift
@@ -8,12 +8,13 @@ import RxSwift
import SearchDomainInterface
import SignInFeatureInterface
import SnapKit
-import SongsDomainInterface
+@preconcurrency import SongsDomainInterface
import Then
import UIKit
import Utility
-final class SongSearchResultViewController: BaseReactorViewController, SongCartViewType {
+final class SongSearchResultViewController: BaseReactorViewController,
+ @preconcurrency SongCartViewType {
var songCartView: SongCartView!
var bottomSheetView: BottomSheetView!
@@ -308,10 +309,12 @@ extension SongSearchResultViewController: UICollectionViewDelegate {
}
extension SongSearchResultViewController: SearchSortOptionDelegate {
- func updateSortType(_ type: SortType) {
- LogManager.analytics(SearchAnalyticsLog.selectSearchSort(option: type.rawValue, category: "song"))
- if reactor?.currentState.sortType != type {
- reactor?.action.onNext(.changeSortType(type))
+ nonisolated func updateSortType(_ type: SortType) {
+ Task { @MainActor in
+ LogManager.analytics(SearchAnalyticsLog.selectSearchSort(option: type.rawValue, category: "song"))
+ if reactor?.currentState.sortType != type {
+ reactor?.action.onNext(.changeSortType(type))
+ }
}
}
}
@@ -353,7 +356,7 @@ extension SongSearchResultViewController: SongCartViewDelegate {
return
}
- if PreferenceManager.userInfo == nil {
+ if PreferenceManager.shared.userInfo == nil {
let vc = self.textPopupFactory.makeView(
text: LocalizationStrings.needLoginWarning,
cancelButtonIsHidden: false,
diff --git a/Projects/Features/SearchFeature/Sources/Before/Components/BeforeSearchComponent.swift b/Projects/Features/SearchFeature/Sources/Before/Components/BeforeSearchComponent.swift
index 505f41217..31ea643e8 100644
--- a/Projects/Features/SearchFeature/Sources/Before/Components/BeforeSearchComponent.swift
+++ b/Projects/Features/SearchFeature/Sources/Before/Components/BeforeSearchComponent.swift
@@ -15,6 +15,7 @@ public protocol BeforeSearchDependency: Dependency {
var playlistDetailFactory: any PlaylistDetailFactory { get }
}
+@MainActor
public final class BeforeSearchComponent: Component {
public func makeView() -> UIViewController {
return BeforeSearchContentViewController(
diff --git a/Projects/Features/SearchFeature/Sources/Before/Components/WakmusicRecommendComponent.swift b/Projects/Features/SearchFeature/Sources/Before/Components/WakmusicRecommendComponent.swift
index 19ff30e17..0934305ee 100644
--- a/Projects/Features/SearchFeature/Sources/Before/Components/WakmusicRecommendComponent.swift
+++ b/Projects/Features/SearchFeature/Sources/Before/Components/WakmusicRecommendComponent.swift
@@ -9,6 +9,7 @@ public protocol WakmusicRecommendDependency: Dependency {
var wakmusicPlaylistDetailFactory: any WakmusicPlaylistDetailFactory { get }
}
+@MainActor
public final class WakmusicRecommendComponent: Component {
public func makeView() -> UIViewController {
let reactor = WakmusicRecommendReactor(
diff --git a/Projects/Features/SearchFeature/Sources/Before/CompositionalLayout/Enum/DataSource/BeforeVcDataSoruce.swift b/Projects/Features/SearchFeature/Sources/Before/CompositionalLayout/Enum/DataSource/BeforeVcDataSoruce.swift
index 1be895d53..cd87f2620 100644
--- a/Projects/Features/SearchFeature/Sources/Before/CompositionalLayout/Enum/DataSource/BeforeVcDataSoruce.swift
+++ b/Projects/Features/SearchFeature/Sources/Before/CompositionalLayout/Enum/DataSource/BeforeVcDataSoruce.swift
@@ -4,7 +4,7 @@ import PlaylistDomainInterface
#warning("์ค์ ๋ฐ์ดํฐ entity๋ก ๋ฐ๊พธ๊ธฐ")
-enum BeforeVcDataSoruce: Hashable {
+enum BeforeVcDataSoruce: Hashable, Sendable {
case youtube(model: CurrentVideoEntity)
case recommend(model: RecommendPlaylistEntity)
// case popularList(model: Model)
diff --git a/Projects/Features/SearchFeature/Sources/Before/ViewControllers/BeforeSearchContentViewController.swift b/Projects/Features/SearchFeature/Sources/Before/ViewControllers/BeforeSearchContentViewController.swift
index 5e3127969..d2d13dc1c 100644
--- a/Projects/Features/SearchFeature/Sources/Before/ViewControllers/BeforeSearchContentViewController.swift
+++ b/Projects/Features/SearchFeature/Sources/Before/ViewControllers/BeforeSearchContentViewController.swift
@@ -131,7 +131,7 @@ final class BeforeSearchContentViewController: BaseReactorViewController, ContainerViewType,
+final class SearchViewController: BaseStoryboardReactorViewController, @preconcurrency ContainerViewType,
EqualHandleTappedType {
private enum Font {
static let headerFontSize: CGFloat = 16
@@ -312,15 +312,17 @@ extension SearchViewController {
}
extension SearchViewController {
- public func equalHandleTapped() {
- let viewControllersCount: Int = self.navigationController?.viewControllers.count ?? 0
- if viewControllersCount > 1 {
- self.navigationController?.popToRootViewController(animated: true)
- } else {
- if let before = children.first as? BeforeSearchContentViewController {
- before.scrollToTop()
- } else if let after = children.first as? AfterSearchViewController {
- after.scrollToTop()
+ public nonisolated func equalHandleTapped() {
+ Task { @MainActor in
+ let viewControllersCount: Int = self.navigationController?.viewControllers.count ?? 0
+ if viewControllersCount > 1 {
+ self.navigationController?.popToRootViewController(animated: true)
+ } else {
+ if let before = children.first as? BeforeSearchContentViewController {
+ before.scrollToTop()
+ } else if let after = children.first as? AfterSearchViewController {
+ after.scrollToTop()
+ }
}
}
}
diff --git a/Projects/Features/SearchFeature/Sources/Service/SearchCommonService.swift b/Projects/Features/SearchFeature/Sources/Service/SearchCommonService.swift
index 5308ac617..bd4003908 100644
--- a/Projects/Features/SearchFeature/Sources/Service/SearchCommonService.swift
+++ b/Projects/Features/SearchFeature/Sources/Service/SearchCommonService.swift
@@ -1,5 +1,5 @@
import Foundation
-import RxSwift
+@preconcurrency import RxSwift
import SearchFeatureInterface
protocol SearchCommonService {
@@ -7,7 +7,7 @@ protocol SearchCommonService {
var recentText: PublishSubject { get }
}
-final class DefaultSearchCommonService: SearchCommonService {
+final class DefaultSearchCommonService: SearchCommonService, Sendable {
let typingStatus: BehaviorSubject = .init(value: .before)
let recentText: PublishSubject = .init()
diff --git a/Projects/Features/SignInFeature/Interface/SignInFactory.swift b/Projects/Features/SignInFeature/Interface/SignInFactory.swift
index 3fa1aaf51..d2b333990 100644
--- a/Projects/Features/SignInFeature/Interface/SignInFactory.swift
+++ b/Projects/Features/SignInFeature/Interface/SignInFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol SignInFactory {
func makeView() -> UIViewController
}
diff --git a/Projects/Features/SignInFeature/Sources/ViewModels/LoginViewModel.swift b/Projects/Features/SignInFeature/Sources/ViewModels/LoginViewModel.swift
index c6281dcf9..655f1d327 100644
--- a/Projects/Features/SignInFeature/Sources/ViewModels/LoginViewModel.swift
+++ b/Projects/Features/SignInFeature/Sources/ViewModels/LoginViewModel.swift
@@ -3,13 +3,13 @@ import AuthenticationServices
import BaseFeature
import Localization
import LogManager
-import NaverThirdPartyLogin
-import RxRelay
+@preconcurrency import NaverThirdPartyLogin
+@preconcurrency import RxRelay
import RxSwift
import UserDomainInterface
import Utility
-public final class LoginViewModel: NSObject { // ๋ค์ด๋ฒ ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ๋ฐ๊ธฐ์ํ NSObject ์์
+public final class LoginViewModel: NSObject, @unchecked Sendable { // ๋ค์ด๋ฒ ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ๋ฐ๊ธฐ์ํ NSObject ์์
private let fetchTokenUseCase: FetchTokenUseCase
private let fetchUserInfoUseCase: FetchUserInfoUseCase
let input: Input = Input()
@@ -40,7 +40,9 @@ public final class LoginViewModel: NSObject { // ๋ค์ด๋ฒ ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ
self.fetchUserInfoUseCase = fetchUserInfoUseCase
super.init()
GoogleLoginManager.shared.googleOAuthLoginDelegate = self
- NaverThirdPartyLoginConnection.getSharedInstance()?.delegate = self
+ Task { @MainActor in
+ NaverThirdPartyLoginConnection.getSharedInstance().delegate = self
+ }
bind()
}
}
@@ -49,8 +51,10 @@ private extension LoginViewModel {
func bind() {
input.didTapNaverLoginButton
.bind(with: self, onNext: { owner, _ in
- NaverThirdPartyLoginConnection.getSharedInstance()?.delegate = owner
- NaverThirdPartyLoginConnection.getSharedInstance()?.requestThirdPartyLogin()
+ Task { @MainActor in
+ NaverThirdPartyLoginConnection.getSharedInstance()?.delegate = owner
+ NaverThirdPartyLoginConnection.getSharedInstance()?.requestThirdPartyLogin()
+ }
})
.disposed(by: disposeBag)
@@ -103,32 +107,37 @@ private extension LoginViewModel {
extension LoginViewModel: GoogleOAuthLoginDelegate {
public func requestGoogleAccessToken(_ code: String) {
- Task {
+ let arrivedTokenFromThirdParty = input.arrivedTokenFromThirdParty
+ Task { @MainActor in
let id = try await GoogleLoginManager.shared.getGoogleOAuthToken(code)
let log = SigninAnalyticsLog.completeSocialLogin(type: .google)
LogManager.analytics(log)
- input.arrivedTokenFromThirdParty.accept((.google, id))
+ arrivedTokenFromThirdParty.accept((.google, id))
}
}
}
extension LoginViewModel: NaverThirdPartyLoginConnectionDelegate {
public func oauth20ConnectionDidFinishRequestACTokenWithAuthCode() {
- let shared = NaverThirdPartyLoginConnection.getSharedInstance()
- guard let accessToken = shared?.accessToken else { return }
- let log = SigninAnalyticsLog.completeSocialLogin(type: .naver)
- LogManager.analytics(log)
+ let arrivedTokenFromThirdParty = input.arrivedTokenFromThirdParty
+ Task { @MainActor in
+ guard let accessToken = NaverThirdPartyLoginConnection.getSharedInstance().accessToken else { return }
+ let log = SigninAnalyticsLog.completeSocialLogin(type: .naver)
+ LogManager.analytics(log)
- input.arrivedTokenFromThirdParty.accept((.naver, accessToken))
+ arrivedTokenFromThirdParty.accept((.naver, accessToken))
+ }
}
public func oauth20ConnectionDidFinishRequestACTokenWithRefreshToken() {
- let shared = NaverThirdPartyLoginConnection.getSharedInstance()
- guard let accessToken = shared?.accessToken else { return }
- let log = SigninAnalyticsLog.completeSocialLogin(type: .naver)
- LogManager.analytics(log)
+ let arrivedTokenFromThirdParty = input.arrivedTokenFromThirdParty
+ Task { @MainActor in
+ guard let accessToken = NaverThirdPartyLoginConnection.getSharedInstance().accessToken else { return }
+ let log = SigninAnalyticsLog.completeSocialLogin(type: .naver)
+ LogManager.analytics(log)
- input.arrivedTokenFromThirdParty.accept((.naver, accessToken))
+ arrivedTokenFromThirdParty.accept((.naver, accessToken))
+ }
}
public func oauth20ConnectionDidFinishDeleteToken() {
diff --git a/Projects/Features/SignInFeature/Testing/SignInComponentStub.swift b/Projects/Features/SignInFeature/Testing/SignInComponentStub.swift
index 6296866ce..6761dfd27 100644
--- a/Projects/Features/SignInFeature/Testing/SignInComponentStub.swift
+++ b/Projects/Features/SignInFeature/Testing/SignInComponentStub.swift
@@ -7,7 +7,7 @@ import UIKit
import UserDomainInterface
@testable import UserDomainTesting
-public final class SignInComponentStub: SignInFactory {
+public final class SignInComponentStub: SignInFactory, @unchecked Sendable {
public func makeView() -> UIViewController {
return LoginViewController.viewController(
viewModel: .init(
diff --git a/Projects/Features/SongCreditFeature/Demo/Sources/AppDelegate.swift b/Projects/Features/SongCreditFeature/Demo/Sources/AppDelegate.swift
index 04ffc7ed7..c8febd366 100644
--- a/Projects/Features/SongCreditFeature/Demo/Sources/AppDelegate.swift
+++ b/Projects/Features/SongCreditFeature/Demo/Sources/AppDelegate.swift
@@ -45,14 +45,14 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
}
}
-final class DummyCreditSongListFactory: CreditSongListFactory {
+final class DummyCreditSongListFactory: CreditSongListFactory, @unchecked Sendable {
func makeViewController(workerName: String) -> UIViewController {
let viewController = UIViewController()
return viewController
}
}
-final class DummyArtistDetailFactory: ArtistDetailFactory {
+final class DummyArtistDetailFactory: ArtistDetailFactory, @unchecked Sendable {
func makeView(artistID: String) -> UIViewController {
return UIViewController()
}
diff --git a/Projects/Features/SongCreditFeature/Interface/SongCreditFactory.swift b/Projects/Features/SongCreditFeature/Interface/SongCreditFactory.swift
index 456c542ff..59b9fd729 100644
--- a/Projects/Features/SongCreditFeature/Interface/SongCreditFactory.swift
+++ b/Projects/Features/SongCreditFeature/Interface/SongCreditFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol SongCreditFactory {
func makeViewController(songID: String) -> UIViewController
}
diff --git a/Projects/Features/StorageFeature/Sources/Components/LikeStorageComponent.swift b/Projects/Features/StorageFeature/Sources/Components/LikeStorageComponent.swift
index 11f9c53f5..436352cce 100644
--- a/Projects/Features/StorageFeature/Sources/Components/LikeStorageComponent.swift
+++ b/Projects/Features/StorageFeature/Sources/Components/LikeStorageComponent.swift
@@ -19,6 +19,7 @@ public protocol LikeStorageDependency: Dependency {
var songDetailPresenter: any SongDetailPresentable { get }
}
+@MainActor
public final class LikeStorageComponent: Component {
public func makeView() -> UIViewController {
return LikeStorageViewController.viewController(
diff --git a/Projects/Features/StorageFeature/Sources/Components/ListStorageComponent.swift b/Projects/Features/StorageFeature/Sources/Components/ListStorageComponent.swift
index 311867607..17d389c2f 100644
--- a/Projects/Features/StorageFeature/Sources/Components/ListStorageComponent.swift
+++ b/Projects/Features/StorageFeature/Sources/Components/ListStorageComponent.swift
@@ -26,6 +26,7 @@ public protocol ListStorageDependency: Dependency {
var fruitDrawFactory: any FruitDrawFactory { get }
}
+@MainActor
public final class ListStorageComponent: Component {
public func makeView() -> UIViewController {
return ListStorageViewController(
diff --git a/Projects/Features/StorageFeature/Sources/Reactors/LikeStorageReactor.swift b/Projects/Features/StorageFeature/Sources/Reactors/LikeStorageReactor.swift
index e2b810f06..a6dbab580 100644
--- a/Projects/Features/StorageFeature/Sources/Reactors/LikeStorageReactor.swift
+++ b/Projects/Features/StorageFeature/Sources/Reactors/LikeStorageReactor.swift
@@ -248,7 +248,7 @@ final class LikeStorageReactor: Reactor {
extension LikeStorageReactor {
func viewDidLoad() -> Observable {
- let isLoggedIn = PreferenceManager.userInfo != nil
+ let isLoggedIn = PreferenceManager.shared.userInfo != nil
if !isLoggedIn { return .empty() }
return .concat(
updateIsLoggedIn(isLoggedIn),
@@ -332,10 +332,12 @@ extension LikeStorageReactor {
func playWithAddToCurrentPlaylist(song: FavoriteSongEntity) -> Observable {
let appendingPlaylisItem = PlaylistItem(id: song.songID, title: song.title, artist: song.artist)
PlayState.shared.append(item: appendingPlaylisItem)
- WakmusicYoutubePlayer(
- id: song.songID,
- playPlatform: song.title.isContainShortsTagTitle ? .youtube : .automatic
- ).play()
+ Task { @MainActor in
+ WakmusicYoutubePlayer(
+ id: song.songID,
+ playPlatform: song.title.isContainShortsTagTitle ? .youtube : .automatic
+ ).play()
+ }
return .empty()
}
diff --git a/Projects/Features/StorageFeature/Sources/Reactors/ListStorageReactor.swift b/Projects/Features/StorageFeature/Sources/Reactors/ListStorageReactor.swift
index 8bf963e4f..da5d94d5d 100644
--- a/Projects/Features/StorageFeature/Sources/Reactors/ListStorageReactor.swift
+++ b/Projects/Features/StorageFeature/Sources/Reactors/ListStorageReactor.swift
@@ -7,7 +7,7 @@ import PriceDomainInterface
import ReactorKit
import RxCocoa
import RxSwift
-import SongsDomainInterface
+@preconcurrency import SongsDomainInterface
import UserDomainInterface
import Utility
@@ -280,7 +280,7 @@ final class ListStorageReactor: Reactor {
extension ListStorageReactor {
func viewDidLoad() -> Observable {
- let isLoggedIn = PreferenceManager.userInfo != nil
+ let isLoggedIn = PreferenceManager.shared.userInfo != nil
if !isLoggedIn { return .empty() }
return .concat(
updateIsLoggedIn(isLoggedIn),
@@ -366,7 +366,7 @@ extension ListStorageReactor {
}
func addToCurrentPlaylist() -> Observable {
- let limit = 50
+ _ = 50
let selectedPlaylists = currentState.dataSource
.flatMap { $0.items.filter { $0.isSelected == true } }
@@ -424,12 +424,15 @@ extension ListStorageReactor {
.asObservable()
.do(onNext: { [weak self] appendingPlaylistItems in
PlayState.shared.appendSongsToPlaylist(appendingPlaylistItems)
- let ids = appendingPlaylistItems.map { $0.id }
- .prefix(50)
- if appendingPlaylistItems.allSatisfy({ $0.title.isContainShortsTagTitle }) {
- WakmusicYoutubePlayer(ids: Array(ids), title: "์ํ๋ฒ์ค ๋ฎค์ง", playPlatform: .youtube).play()
- } else {
- WakmusicYoutubePlayer(ids: Array(ids), title: "์ํ๋ฒ์ค ๋ฎค์ง").play()
+ Task { @MainActor in
+ let ids = appendingPlaylistItems.map { $0.id }
+ .prefix(50)
+
+ if appendingPlaylistItems.allSatisfy({ $0.title.isContainShortsTagTitle }) {
+ WakmusicYoutubePlayer(ids: Array(ids), title: "์ํ๋ฒ์ค ๋ฎค์ง", playPlatform: .youtube).play()
+ } else {
+ WakmusicYoutubePlayer(ids: Array(ids), title: "์ํ๋ฒ์ค ๋ฎค์ง").play()
+ }
}
self?.storageCommonService.isEditingState.onNext(false)
})
@@ -525,7 +528,7 @@ private extension ListStorageReactor {
func mutateDeletePlaylist(_ playlists: [PlaylistEntity]) -> Observable {
let noti = NotificationCenter.default
- let subscribedPlaylistKeys = playlists.filter { $0.userId != PreferenceManager.userInfo?.decryptedID }
+ let subscribedPlaylistKeys = playlists.filter { $0.userId != PreferenceManager.shared.userInfo?.decryptedID }
.map { $0.key }
let ids = playlists.map { $0.key }
return deletePlayListUseCase.execute(ids: ids)
@@ -572,7 +575,7 @@ private extension ListStorageReactor {
.asObservable()
.map { $0.price }
.flatMap { price -> Observable in
- guard let userItemCount = PreferenceManager.userInfo?.itemCount else {
+ guard let userItemCount = PreferenceManager.shared.userInfo?.itemCount else {
return .just(.showToast(LocalizationStrings.unknownErrorWarning))
}
if userItemCount < price {
diff --git a/Projects/Features/StorageFeature/Sources/Reactors/StorageReactor.swift b/Projects/Features/StorageFeature/Sources/Reactors/StorageReactor.swift
index 9dd6afd12..230875d7d 100644
--- a/Projects/Features/StorageFeature/Sources/Reactors/StorageReactor.swift
+++ b/Projects/Features/StorageFeature/Sources/Reactors/StorageReactor.swift
@@ -97,7 +97,7 @@ final class StorageReactor: Reactor {
private extension StorageReactor {
func viewDidLoad() -> Observable {
- let isLoggedIn = PreferenceManager.userInfo != nil
+ let isLoggedIn = PreferenceManager.shared.userInfo != nil
return .just(.updateIsLoggedIn(isLoggedIn))
}
diff --git a/Projects/Features/StorageFeature/Sources/Service/StorageCommonService.swift b/Projects/Features/StorageFeature/Sources/Service/StorageCommonService.swift
index 13fd28f04..cf2ef16a9 100644
--- a/Projects/Features/StorageFeature/Sources/Service/StorageCommonService.swift
+++ b/Projects/Features/StorageFeature/Sources/Service/StorageCommonService.swift
@@ -1,5 +1,5 @@
import Foundation
-import RxSwift
+@preconcurrency import RxSwift
import Utility
protocol StorageCommonService {
@@ -9,7 +9,7 @@ protocol StorageCommonService {
var likeListRefreshEvent: Observable { get }
}
-final class DefaultStorageCommonService: StorageCommonService {
+final class DefaultStorageCommonService: StorageCommonService, Sendable {
static let shared = DefaultStorageCommonService()
let isEditingState: BehaviorSubject
@@ -20,7 +20,7 @@ final class DefaultStorageCommonService: StorageCommonService {
init() {
let notificationCenter = NotificationCenter.default
isEditingState = .init(value: false)
- loginStateDidChangedEvent = PreferenceManager.$userInfo.map(\.?.ID).distinctUntilChanged().skip(1)
+ loginStateDidChangedEvent = PreferenceManager.shared.$userInfo.map(\.?.ID).distinctUntilChanged().skip(1)
playlistRefreshEvent = notificationCenter.rx.notification(.shouldRefreshPlaylist)
likeListRefreshEvent = notificationCenter.rx.notification(.shouldRefreshLikeList).map { _ in () }
}
diff --git a/Projects/Features/StorageFeature/Sources/ViewControllers/LikeStorageViewController.swift b/Projects/Features/StorageFeature/Sources/ViewControllers/LikeStorageViewController.swift
index 77d25a7d3..b6f2fffd6 100644
--- a/Projects/Features/StorageFeature/Sources/ViewControllers/LikeStorageViewController.swift
+++ b/Projects/Features/StorageFeature/Sources/ViewControllers/LikeStorageViewController.swift
@@ -17,7 +17,7 @@ import Utility
typealias LikeSectionModel = SectionModel
-final class LikeStorageViewController: BaseReactorViewController, SongCartViewType {
+final class LikeStorageViewController: BaseReactorViewController, @preconcurrency SongCartViewType {
let likeStorageView = LikeStorageView()
var containSongsFactory: ContainSongsFactory!
@@ -151,7 +151,7 @@ final class LikeStorageViewController: BaseReactorViewController
-final class ListStorageViewController: BaseReactorViewController, SongCartViewType,
+final class ListStorageViewController: BaseReactorViewController, @preconcurrency SongCartViewType,
PlaylistDetailNavigator {
private let createListButton = CreateListButtonView(
padding: .init(
@@ -206,7 +206,7 @@ final class ListStorageViewController: BaseReactorViewController Int {
self.viewControllers.count
}
@@ -244,12 +244,14 @@ extension StorageViewController: EqualHandleTappedType {
}
}
- public func equalHandleTapped() {
- let viewControllersCount: Int = self.navigationController?.viewControllers.count ?? 0
- if viewControllersCount > 1 {
- self.navigationController?.popToRootViewController(animated: true)
- } else {
- scrollToTop()
+ public nonisolated func equalHandleTapped() {
+ Task { @MainActor in
+ let viewControllersCount: Int = self.navigationController?.viewControllers.count ?? 0
+ if viewControllersCount > 1 {
+ self.navigationController?.popToRootViewController(animated: true)
+ } else {
+ scrollToTop()
+ }
}
}
}
diff --git a/Projects/Features/StorageFeature/Sources/Views/LikeStorageTableViewCell.swift b/Projects/Features/StorageFeature/Sources/Views/LikeStorageTableViewCell.swift
index 098a7a9a6..5827b23dd 100644
--- a/Projects/Features/StorageFeature/Sources/Views/LikeStorageTableViewCell.swift
+++ b/Projects/Features/StorageFeature/Sources/Views/LikeStorageTableViewCell.swift
@@ -7,6 +7,7 @@ import UIKit
import UserDomainInterface
import Utility
+@MainActor
public protocol LikeStorageTableViewCellDelegate: AnyObject {
func buttonTapped(type: LikeStorageTableViewCellDelegateConstant)
}
diff --git a/Projects/Features/StorageFeature/Sources/Views/LikeStorageView.swift b/Projects/Features/StorageFeature/Sources/Views/LikeStorageView.swift
index 05948a730..6c9ec2e3e 100644
--- a/Projects/Features/StorageFeature/Sources/Views/LikeStorageView.swift
+++ b/Projects/Features/StorageFeature/Sources/Views/LikeStorageView.swift
@@ -14,6 +14,7 @@ import UIKit
import UserDomainInterface
import Utility
+@MainActor
private protocol LikeStorageStateProtocol {
func updateActivityIndicatorState(isPlaying: Bool)
func updateRefreshControlState(isPlaying: Bool)
@@ -134,7 +135,8 @@ extension LikeStorageView: LikeStorageStateProtocol {
}
}
-extension Reactive: LikeStorageActionProtocol where Base: LikeStorageView {
+extension Reactive: @preconcurrency LikeStorageActionProtocol where Base: LikeStorageView {
+ @MainActor
var loginButtonDidTap: Observable {
base.loginWarningView.loginButtonDidTapSubject.asObservable()
}
diff --git a/Projects/Features/StorageFeature/Sources/Views/ListStorageTableViewCell.swift b/Projects/Features/StorageFeature/Sources/Views/ListStorageTableViewCell.swift
index 64f2c330b..f7e8925c6 100644
--- a/Projects/Features/StorageFeature/Sources/Views/ListStorageTableViewCell.swift
+++ b/Projects/Features/StorageFeature/Sources/Views/ListStorageTableViewCell.swift
@@ -8,6 +8,7 @@ import UIKit
import UserDomainInterface
import Utility
+@MainActor
public protocol ListStorageTableViewCellDelegate: AnyObject {
func buttonTapped(type: ListStorageTableViewCellDelegateConstant)
}
diff --git a/Projects/Features/StorageFeature/Sources/Views/ListStorageView.swift b/Projects/Features/StorageFeature/Sources/Views/ListStorageView.swift
index 080cf64a2..a32ad3728 100644
--- a/Projects/Features/StorageFeature/Sources/Views/ListStorageView.swift
+++ b/Projects/Features/StorageFeature/Sources/Views/ListStorageView.swift
@@ -14,6 +14,7 @@ import UIKit
import UserDomainInterface
import Utility
+@MainActor
private protocol ListStorageStateProtocol {
func updateActivityIndicatorState(isPlaying: Bool)
func updateRefreshControlState(isPlaying: Bool)
@@ -190,7 +191,8 @@ extension ListStorageView: ListStorageStateProtocol {
}
}
-extension Reactive: ListStorageActionProtocol where Base: ListStorageView {
+extension Reactive: @preconcurrency ListStorageActionProtocol where Base: ListStorageView {
+ @MainActor
var loginButtonDidTap: Observable {
base.loginWarningView.loginButtonDidTapSubject.asObservable()
}
diff --git a/Projects/Features/StorageFeature/Sources/Views/ParticleAnimationView.swift b/Projects/Features/StorageFeature/Sources/Views/ParticleAnimationView.swift
index c406a7b67..301347c24 100644
--- a/Projects/Features/StorageFeature/Sources/Views/ParticleAnimationView.swift
+++ b/Projects/Features/StorageFeature/Sources/Views/ParticleAnimationView.swift
@@ -5,6 +5,7 @@ import Then
import UIKit
import Utility
+@MainActor
private protocol ParticleAnimationStateProtocol {
func startAnimation()
}
diff --git a/Projects/Features/StorageFeature/Sources/Views/StorageView.swift b/Projects/Features/StorageFeature/Sources/Views/StorageView.swift
index 7f17c65b1..dcb74cc17 100644
--- a/Projects/Features/StorageFeature/Sources/Views/StorageView.swift
+++ b/Projects/Features/StorageFeature/Sources/Views/StorageView.swift
@@ -6,6 +6,7 @@ import Then
import UIKit
import Utility
+@MainActor
private protocol StorageStateProtocol {
func updateIsHiddenEditButton(isHidden: Bool)
}
@@ -16,6 +17,7 @@ private protocol StorageActionProtocol {
}
private enum ButtonAttributed {
+ @MainActor
static let edit = NSMutableAttributedString(
string: "ํธ์ง",
attributes: [
@@ -23,6 +25,7 @@ private enum ButtonAttributed {
.foregroundColor: DesignSystemAsset.BlueGrayColor.blueGray400.color
]
)
+ @MainActor
static let save = NSMutableAttributedString(
string: "์๋ฃ",
attributes: [
diff --git a/Projects/Features/StorageFeature/interface/StorageFactory.swift b/Projects/Features/StorageFeature/interface/StorageFactory.swift
index f478f0d2f..07ffd977a 100644
--- a/Projects/Features/StorageFeature/interface/StorageFactory.swift
+++ b/Projects/Features/StorageFeature/interface/StorageFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol StorageFactory {
func makeView() -> UIViewController
}
diff --git a/Projects/Features/TeamFeature/Interface/TeamInfoFactory.swift b/Projects/Features/TeamFeature/Interface/TeamInfoFactory.swift
index 82a3b2b09..84f145422 100644
--- a/Projects/Features/TeamFeature/Interface/TeamInfoFactory.swift
+++ b/Projects/Features/TeamFeature/Interface/TeamInfoFactory.swift
@@ -1,5 +1,6 @@
import UIKit
+@MainActor
public protocol TeamInfoFactory {
func makeView() -> UIViewController
}
diff --git a/Projects/Features/TeamFeature/Sources/ViewControllers/TeamInfoViewController.swift b/Projects/Features/TeamFeature/Sources/ViewControllers/TeamInfoViewController.swift
index b24112176..f6adfafca 100644
--- a/Projects/Features/TeamFeature/Sources/ViewControllers/TeamInfoViewController.swift
+++ b/Projects/Features/TeamFeature/Sources/ViewControllers/TeamInfoViewController.swift
@@ -170,7 +170,7 @@ private extension TeamInfoViewController {
}
}
-extension TeamInfoViewController: PageboyViewControllerDataSource, TMBarDataSource {
+extension TeamInfoViewController: @preconcurrency PageboyViewControllerDataSource, @preconcurrency TMBarDataSource {
public func barItem(for bar: TMBar, at index: Int) -> TMBarItemable {
return TMBarItem(title: output.teams.value[index])
}
diff --git a/Projects/Features/TeamFeature/Sources/Views/TeamInfoSectionView.swift b/Projects/Features/TeamFeature/Sources/Views/TeamInfoSectionView.swift
index 181a37bc1..1aab07f2f 100644
--- a/Projects/Features/TeamFeature/Sources/Views/TeamInfoSectionView.swift
+++ b/Projects/Features/TeamFeature/Sources/Views/TeamInfoSectionView.swift
@@ -2,6 +2,7 @@ import DesignSystem
import UIKit
import Utility
+@MainActor
protocol TeamInfoSectionViewDelegate: AnyObject {
func toggleSection(header: TeamInfoSectionView, section: Int)
}
diff --git a/Projects/Modules/KeychainModule/Sources/Keychain.swift b/Projects/Modules/KeychainModule/Sources/Keychain.swift
index 1d016e50f..3134385d3 100644
--- a/Projects/Modules/KeychainModule/Sources/Keychain.swift
+++ b/Projects/Modules/KeychainModule/Sources/Keychain.swift
@@ -1,11 +1,11 @@
-public enum KeychainType: String {
+public enum KeychainType: String, Sendable {
case accessToken = "ACCESS-TOKEN"
case refreshToken = "REFRESH-TOKEN"
case accessExpiresIn = "ACCESS-EXPIRES-IN" // ํ ํฐ์ด ๋ง๋ฃ๋ ์๊ฐ์ Miliseconds(timestamp)๋ก ์ ์ฅํด์
case deviceID = "DEVICE-ID"
}
-public protocol Keychain {
+public protocol Keychain: Sendable {
func save(type: KeychainType, value: String)
func load(type: KeychainType) -> String
func delete(type: KeychainType)
diff --git a/Projects/Modules/KeychainModule/Sources/KeychainFake.swift b/Projects/Modules/KeychainModule/Sources/KeychainFake.swift
index cda52e1f3..ec8c21d1d 100644
--- a/Projects/Modules/KeychainModule/Sources/KeychainFake.swift
+++ b/Projects/Modules/KeychainModule/Sources/KeychainFake.swift
@@ -1,6 +1,6 @@
import Foundation
-final class KeychainFake: Keychain {
+final class KeychainFake: Keychain, @unchecked Sendable {
var store: [String: String] = [:]
func save(type: KeychainType, value: String) {
diff --git a/Projects/Modules/LogManager/Sources/AnalyticsLogType.swift b/Projects/Modules/LogManager/Sources/AnalyticsLogType.swift
index 2ec2917be..f46488cba 100644
--- a/Projects/Modules/LogManager/Sources/AnalyticsLogType.swift
+++ b/Projects/Modules/LogManager/Sources/AnalyticsLogType.swift
@@ -1,6 +1,6 @@
import Foundation
-public protocol AnalyticsLogType {
+public protocol AnalyticsLogType: Sendable {
var name: String { get }
var params: [String: Any] { get }
}
diff --git a/Projects/Modules/LogManager/Sources/CommonAnalyticsLog.swift b/Projects/Modules/LogManager/Sources/CommonAnalyticsLog.swift
index 11ae089f0..dfd13a490 100644
--- a/Projects/Modules/LogManager/Sources/CommonAnalyticsLog.swift
+++ b/Projects/Modules/LogManager/Sources/CommonAnalyticsLog.swift
@@ -20,7 +20,7 @@ public enum CommonAnalyticsLog: AnalyticsLogType {
}
public extension CommonAnalyticsLog {
- enum PageName: String, AnalyticsLogEnumParametable {
+ enum PageName: String, AnalyticsLogEnumParametable, Sendable {
case home
case musicDetail = "music_detail"
case musicLyrics = "music_lyrics"
@@ -48,7 +48,7 @@ public extension CommonAnalyticsLog {
}
}
- enum PlaylistItemLocation: String, AnalyticsLogEnumParametable {
+ enum PlaylistItemLocation: String, AnalyticsLogEnumParametable, Sendable {
case home
case storage
case search
@@ -59,7 +59,7 @@ public extension CommonAnalyticsLog {
}
}
- enum PlayButtonLocation: String, AnalyticsLogEnumParametable {
+ enum PlayButtonLocation: String, AnalyticsLogEnumParametable, Sendable {
case home
case search
case artist
@@ -73,7 +73,7 @@ public extension CommonAnalyticsLog {
case creditSongList = "credit_song_list"
}
- enum PlayButtonType: String, AnalyticsLogEnumParametable {
+ enum PlayButtonType: String, AnalyticsLogEnumParametable, Sendable {
case single
case multiple
case all
@@ -83,7 +83,7 @@ public extension CommonAnalyticsLog {
case playlist
}
- enum AddMusicLocation: String, AnalyticsLogEnumParametable {
+ enum AddMusicLocation: String, AnalyticsLogEnumParametable, Sendable {
case songDetail = "song_detail"
case search
case chart
@@ -94,14 +94,14 @@ public extension CommonAnalyticsLog {
case storageLike = "storage_like"
}
- enum EditButtonLocation: String, AnalyticsLogEnumParametable {
+ enum EditButtonLocation: String, AnalyticsLogEnumParametable, Sendable {
case playlistDetail = "playlist_detail"
case myPlaylist = "my_playlist"
case storageLike = "storage_like"
case playlist
}
- enum LoginButtonEntry: String, AnalyticsLogEnumParametable {
+ enum LoginButtonEntry: String, AnalyticsLogEnumParametable, Sendable {
case myPlaylist = "my_playlist"
case storageLike = "storage_like"
case mypage
diff --git a/Projects/Modules/LogManager/Sources/LogHistory/LogHistorySectionItem.swift b/Projects/Modules/LogManager/Sources/LogHistory/LogHistorySectionItem.swift
index 616e7f704..de0c08d62 100644
--- a/Projects/Modules/LogManager/Sources/LogHistory/LogHistorySectionItem.swift
+++ b/Projects/Modules/LogManager/Sources/LogHistory/LogHistorySectionItem.swift
@@ -1,7 +1,7 @@
#if DEBUG || QA
import Foundation
- struct LogHistorySectionItem: Hashable, Equatable {
+ struct LogHistorySectionItem: Hashable, Equatable, Sendable {
let index: Int
let log: any AnalyticsLogType
diff --git a/Projects/Modules/LogManager/Sources/LogHistory/LogHistoryStorage.swift b/Projects/Modules/LogManager/Sources/LogHistory/LogHistoryStorage.swift
index 0b3d8f41d..003317aeb 100644
--- a/Projects/Modules/LogManager/Sources/LogHistory/LogHistoryStorage.swift
+++ b/Projects/Modules/LogManager/Sources/LogHistory/LogHistoryStorage.swift
@@ -1,12 +1,15 @@
#if DEBUG || QA
import Foundation
- final class LogHistoryStorage {
+ final class LogHistoryStorage: @unchecked Sendable {
static let shared = LogHistoryStorage()
+ private let lock = NSRecursiveLock()
private(set) var logHistory: [any AnalyticsLogType] = []
func appendHistory(log: any AnalyticsLogType) {
+ lock.lock()
+ defer { lock.unlock() }
logHistory.append(log)
}
}
diff --git a/Projects/Modules/Utility/Sources/Enums/WMToastOptions.swift b/Projects/Modules/Utility/Sources/Enums/WMToastOptions.swift
index a45ba220f..0fbb08909 100644
--- a/Projects/Modules/Utility/Sources/Enums/WMToastOptions.swift
+++ b/Projects/Modules/Utility/Sources/Enums/WMToastOptions.swift
@@ -1,6 +1,6 @@
import Foundation
-public struct WMToastOptions: OptionSet {
+public struct WMToastOptions: OptionSet, Sendable {
public let rawValue: Int
public static let empty = WMToastOptions(rawValue: 1 << 0)
public static let tabBar = WMToastOptions(rawValue: 1 << 1)
diff --git a/Projects/Modules/Utility/Sources/Enums/YoutubePlayType.swift b/Projects/Modules/Utility/Sources/Enums/YoutubePlayType.swift
index 2743af89d..1d4c47c72 100644
--- a/Projects/Modules/Utility/Sources/Enums/YoutubePlayType.swift
+++ b/Projects/Modules/Utility/Sources/Enums/YoutubePlayType.swift
@@ -1,6 +1,6 @@
import Foundation
-public enum YoutubePlayType: Codable {
+public enum YoutubePlayType: Codable, Sendable {
case youtube
case youtubeMusic
diff --git a/Projects/Modules/Utility/Sources/Extensions/Extension+AVAsset.swift b/Projects/Modules/Utility/Sources/Extensions/Extension+AVAsset.swift
deleted file mode 100644
index 8998ae1ae..000000000
--- a/Projects/Modules/Utility/Sources/Extensions/Extension+AVAsset.swift
+++ /dev/null
@@ -1,20 +0,0 @@
-import AVKit
-import Foundation
-
-public extension AVAsset {
- func generateThumbnail(completion: @escaping (UIImage?) -> Void) {
- DispatchQueue.global().async {
- let imageGenerator = AVAssetImageGenerator(asset: self)
- let time = CMTime(seconds: 0.0, preferredTimescale: 600)
- let times = [NSValue(time: time)]
-
- imageGenerator.generateCGImagesAsynchronously(forTimes: times, completionHandler: { _, image, _, _, _ in
- if let image = image {
- completion(UIImage(cgImage: image))
- } else {
- completion(nil)
- }
- })
- }
- }
-}
diff --git a/Projects/Modules/Utility/Sources/Extensions/Extension+CALayer.swift b/Projects/Modules/Utility/Sources/Extensions/Extension+CALayer.swift
index 97b828b0e..7d37b063a 100644
--- a/Projects/Modules/Utility/Sources/Extensions/Extension+CALayer.swift
+++ b/Projects/Modules/Utility/Sources/Extensions/Extension+CALayer.swift
@@ -23,6 +23,7 @@ public extension CALayer {
UIRectEdge.right, //์ค๋ฅธ์ชฝ
*/
+ @MainActor
func addBorder(_ edges: [UIRectEdge], color: UIColor, height: CGFloat) {
for edge in edges {
let border = CALayer()
@@ -56,6 +57,7 @@ public extension CALayer {
/// - y: ๊ทธ๋ฆผ์ ์์น ์กฐ์ (pt๋จ์) ex) 0
/// - blur: ํผ๊ทธ๋ง ๊ธฐ์ค blur ๊ฐ(pt๋จ์) ex) 20
/// - spread: ํผ๊ทธ๋ง ๊ธฐ์ค spread ๊ฐ(pt๋จ์) ex) 20
+ @MainActor
func addShadow(
color: UIColor,
alpha: Float,
diff --git a/Projects/Modules/Utility/Sources/Extensions/Extension+Double.swift b/Projects/Modules/Utility/Sources/Extensions/Extension+Double.swift
index 12ec0515f..2070795db 100644
--- a/Projects/Modules/Utility/Sources/Extensions/Extension+Double.swift
+++ b/Projects/Modules/Utility/Sources/Extensions/Extension+Double.swift
@@ -18,18 +18,22 @@ public extension Double {
return megabytes / 1024
}
+ @MainActor
var correctLeading: CGFloat {
return self * APP_WIDTH() / 375.0
}
+ @MainActor
var correctTrailing: CGFloat {
return -self * APP_WIDTH() / 375.0
}
+ @MainActor
var correctTop: CGFloat {
return APP_HEIGHT() * (self / 812.0)
}
+ @MainActor
var correctBottom: CGFloat {
return -APP_HEIGHT() * (self / 812.0)
}
diff --git a/Projects/Modules/Utility/Sources/Extensions/Extension+PreferenceManager.swift b/Projects/Modules/Utility/Sources/Extensions/Extension+PreferenceManager.swift
index c319761e4..84e7ffafb 100644
--- a/Projects/Modules/Utility/Sources/Extensions/Extension+PreferenceManager.swift
+++ b/Projects/Modules/Utility/Sources/Extensions/Extension+PreferenceManager.swift
@@ -16,7 +16,7 @@ public extension PreferenceManager {
/// - Parameter word: ์ต๊ทผ ๊ฒ์์ด
func addRecentRecords(word: String) {
let maxSize: Int = 10
- var currentRecentRecords = Utility.PreferenceManager.recentRecords ?? []
+ var currentRecentRecords = Utility.PreferenceManager.shared.recentRecords ?? []
if currentRecentRecords.contains(word) {
if let i = currentRecentRecords.firstIndex(where: { $0 == word }) {
@@ -31,19 +31,19 @@ public extension PreferenceManager {
currentRecentRecords.insert(word, at: 0)
}
- Utility.PreferenceManager.recentRecords = currentRecentRecords
+ Utility.PreferenceManager.shared.recentRecords = currentRecentRecords
}
/// ์ต๊ทผ ๊ฒ์์ด๋ฅผ ์ญ์
/// - Parameter word: ์ต๊ทผ ๊ฒ์์ด
func removeRecentRecords(word: String) {
- var currentRecentRecords = Utility.PreferenceManager.recentRecords ?? []
+ var currentRecentRecords = Utility.PreferenceManager.shared.recentRecords ?? []
if let i = currentRecentRecords.firstIndex(where: { $0 == word }) {
currentRecentRecords.remove(at: i)
}
- Utility.PreferenceManager.recentRecords = currentRecentRecords
+ Utility.PreferenceManager.shared.recentRecords = currentRecentRecords
}
/// ์ ์ ์ ๋ณด ์ ์ฅ
@@ -61,7 +61,7 @@ public extension PreferenceManager {
name: AES256.encrypt(string: name),
itemCount: itemCount
)
- Utility.PreferenceManager.userInfo = userInfo
+ Utility.PreferenceManager.shared.userInfo = userInfo
LogManager.setUserProperty(property: .fruitTotal(count: userInfo.itemCount))
LogManager.setUserProperty(property: .loginPlatform(platform: userInfo.platform))
}
@@ -69,7 +69,7 @@ public extension PreferenceManager {
static func clearUserInfo() {
LogManager.setUserID(userID: nil)
Crashlytics.crashlytics().setUserID(nil)
- PreferenceManager.userInfo = nil
+ PreferenceManager.shared.userInfo = nil
LogManager.clearUserProperty(property: .fruitTotal(count: -1))
LogManager.clearUserProperty(property: .loginPlatform(platform: ""))
}
diff --git a/Projects/Modules/Utility/Sources/Extensions/Extension+UIControl.swift b/Projects/Modules/Utility/Sources/Extensions/Extension+UIControl.swift
index 2e4411da6..b4eb6c12b 100644
--- a/Projects/Modules/Utility/Sources/Extensions/Extension+UIControl.swift
+++ b/Projects/Modules/Utility/Sources/Extensions/Extension+UIControl.swift
@@ -10,13 +10,15 @@ import Combine
import Foundation
import UIKit
+@MainActor
extension UIControl {
func controlPublisher(for event: UIControl.Event) -> UIControl.EventPublisher {
return UIControl.EventPublisher(control: self, event: event)
}
/// Publisher
- struct EventPublisher: Publisher {
+ @MainActor
+ struct EventPublisher: @preconcurrency Publisher {
typealias Output = UIControl
typealias Failure = Never
@@ -30,7 +32,8 @@ extension UIControl {
}
/// Subscription
- fileprivate class EventSubscription: Subscription
+ @MainActor
+ fileprivate class EventSubscription: Subscription, Sendable
where EventSubscriber.Input == UIControl, EventSubscriber.Failure == Never {
let control: UIControl
let event: UIControl.Event
@@ -44,11 +47,20 @@ extension UIControl {
control.addTarget(self, action: #selector(eventDidOccur), for: event)
}
- func request(_ demand: Subscribers.Demand) {}
+ nonisolated func request(_ demand: Subscribers.Demand) {}
- func cancel() {
- subscriber = nil
- control.removeTarget(self, action: #selector(eventDidOccur), for: event)
+ nonisolated func cancel() {
+ if Thread.isMainThread {
+ MainActor.assumeIsolated {
+ subscriber = nil
+ control.removeTarget(self, action: #selector(eventDidOccur), for: event)
+ }
+ } else {
+ Task { @MainActor in
+ subscriber = nil
+ control.removeTarget(self, action: #selector(eventDidOccur), for: event)
+ }
+ }
}
@objc func eventDidOccur() {
diff --git a/Projects/Modules/Utility/Sources/Extensions/Extension+UIPanGestureRecognizer.swift b/Projects/Modules/Utility/Sources/Extensions/Extension+UIPanGestureRecognizer.swift
index 0c8b8a821..719d0e95f 100644
--- a/Projects/Modules/Utility/Sources/Extensions/Extension+UIPanGestureRecognizer.swift
+++ b/Projects/Modules/Utility/Sources/Extensions/Extension+UIPanGestureRecognizer.swift
@@ -10,7 +10,7 @@ import Foundation
import UIKit
public extension UIPanGestureRecognizer {
- struct PanGestureDirection: OptionSet {
+ struct PanGestureDirection: OptionSet, Sendable {
public let rawValue: UInt8
public init(rawValue: UInt8) {
diff --git a/Projects/Modules/Utility/Sources/Extensions/Extension+UIStackView.swift b/Projects/Modules/Utility/Sources/Extensions/Extension+UIStackView.swift
index b6b52debe..00f5b98e9 100644
--- a/Projects/Modules/Utility/Sources/Extensions/Extension+UIStackView.swift
+++ b/Projects/Modules/Utility/Sources/Extensions/Extension+UIStackView.swift
@@ -2,6 +2,6 @@ import UIKit
public extension UIStackView {
func addArrangedSubviews(_ views: UIView...) {
- views.forEach(self.addArrangedSubview(_:))
+ views.forEach { self.addArrangedSubview($0) }
}
}
diff --git a/Projects/Modules/Utility/Sources/Extensions/Extension+UITapGesutreRecognizer.swift b/Projects/Modules/Utility/Sources/Extensions/Extension+UITapGesutreRecognizer.swift
index ebf4b6cee..f9bfaaeae 100644
--- a/Projects/Modules/Utility/Sources/Extensions/Extension+UITapGesutreRecognizer.swift
+++ b/Projects/Modules/Utility/Sources/Extensions/Extension+UITapGesutreRecognizer.swift
@@ -11,8 +11,8 @@ import Foundation
import UIKit
/// UIControl ์ ์์๋ฐ์ง ์๋ UIView ๋ฑ์ ์ด๋ฒคํธ๋ฅผ Combine ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ Publisher ์
๋๋ค.
-public extension UITapGestureRecognizer {
- struct GesturePublisher: Publisher {
+extension UITapGestureRecognizer {
+ struct GesturePublisher: @preconcurrency Publisher {
public typealias Output = TapRecognizer
public typealias Failure = Never
@@ -24,6 +24,7 @@ public extension UITapGestureRecognizer {
self.view = view
}
+ @MainActor
public func receive(subscriber: S) where S: Subscriber, Never == S.Failure, TapRecognizer == S.Input {
let subscription = GestureSubscription(
subscriber: subscriber,
@@ -34,6 +35,7 @@ public extension UITapGestureRecognizer {
}
}
+ @MainActor
final class GestureSubscription: Subscription
where S.Input == TapRecognizer {
private var subscriber: S?
@@ -46,10 +48,18 @@ public extension UITapGestureRecognizer {
view.addGestureRecognizer(recognizer)
}
- public func request(_ demand: Subscribers.Demand) {}
+ public nonisolated func request(_ demand: Subscribers.Demand) {}
- public func cancel() {
- subscriber = nil
+ public nonisolated func cancel() {
+ if Thread.isMainThread {
+ MainActor.assumeIsolated {
+ subscriber = nil
+ }
+ } else {
+ Task { @MainActor in
+ subscriber = nil
+ }
+ }
}
@objc func eventHandler() {
diff --git a/Projects/Modules/Utility/Sources/Extensions/Extension+UIView.swift b/Projects/Modules/Utility/Sources/Extensions/Extension+UIView.swift
index cc153cec1..15c524d0f 100644
--- a/Projects/Modules/Utility/Sources/Extensions/Extension+UIView.swift
+++ b/Projects/Modules/Utility/Sources/Extensions/Extension+UIView.swift
@@ -110,7 +110,7 @@ public extension UIView {
}
func addSubviews(_ views: UIView...) {
- views.forEach(self.addSubview(_:))
+ views.forEach { self.addSubview($0) }
}
var asImage: UIImage {
diff --git a/Projects/Modules/Utility/Sources/GoogleOAuth/GoogleLoginManager.swift b/Projects/Modules/Utility/Sources/GoogleOAuth/GoogleLoginManager.swift
index 278f28367..0230ba6ad 100644
--- a/Projects/Modules/Utility/Sources/GoogleOAuth/GoogleLoginManager.swift
+++ b/Projects/Modules/Utility/Sources/GoogleOAuth/GoogleLoginManager.swift
@@ -25,7 +25,7 @@ public enum WMGoogleError: Error {
case internalError
}
-public class GoogleLoginManager {
+public class GoogleLoginManager: @unchecked Sendable {
// MARK: - ๋ณ์ ์ ์ธ
private let googleURL = "https://accounts.google.com/o/oauth2/v2/auth"
private let accessTokenGoogleURL = "https://oauth2.googleapis.com"
@@ -52,10 +52,12 @@ public class GoogleLoginManager {
components?.queryItems = [scope, responseType, codeChallenge, redirectURI, clientID, codeChallengeMethod]
- if let url = components?.url, UIApplication.shared.canOpenURL(url) {
- LogManager.printDebug(url)
- let safari = SFSafariViewController(url: url)
- UIApplication.topVisibleViewController()?.present(safari, animated: true)
+ Task { @MainActor in
+ if let url = components?.url, UIApplication.shared.canOpenURL(url) {
+ LogManager.printDebug(url)
+ let safari = SFSafariViewController(url: url)
+ UIApplication.topVisibleViewController()?.present(safari, animated: true)
+ }
}
}
diff --git a/Projects/Modules/Utility/Sources/Manager/HapticManager.swift b/Projects/Modules/Utility/Sources/Manager/HapticManager.swift
index bb842bd6f..d3294efa3 100644
--- a/Projects/Modules/Utility/Sources/Manager/HapticManager.swift
+++ b/Projects/Modules/Utility/Sources/Manager/HapticManager.swift
@@ -19,7 +19,8 @@ import UIKit
// HapticManager.shared.impact(style: .rigid)
// HapticManager.shared.impact(style: .soft)
-public class HapticManager {
+@MainActor
+public class HapticManager: Sendable {
public static let shared = HapticManager()
public func notification(type: UINotificationFeedbackGenerator.FeedbackType) {
diff --git a/Projects/Modules/Utility/Sources/Manager/PreferenceManager.swift b/Projects/Modules/Utility/Sources/Manager/PreferenceManager.swift
index c3f1df5e6..d2f4a189b 100644
--- a/Projects/Modules/Utility/Sources/Manager/PreferenceManager.swift
+++ b/Projects/Modules/Utility/Sources/Manager/PreferenceManager.swift
@@ -10,7 +10,7 @@ import Foundation
import RxSwift
/// UserDefaults์ ํธ๋ฆฌํ๊ฒ ์ ๊ทผํ๊ธฐ ์ํ ํด๋์ค ์ ์
-public final class PreferenceManager {
+public final class PreferenceManager: @unchecked Sendable {
public static let shared: PreferenceManager = PreferenceManager()
/// UserDefaults์ ์ ์ฅ ๋ ๋ฐ์ดํฐ์ ์ ๊ทผํ๊ธฐ ์ํ ํค ๊ฐ์ ๋์ด.
@@ -26,38 +26,57 @@ public final class PreferenceManager {
}
@UserDefaultWrapper(key: Constants.recentRecords.rawValue, defaultValue: nil)
- public static var recentRecords: [String]?
+ public var recentRecords: [String]?
@UserDefaultWrapper(key: Constants.startPage.rawValue, defaultValue: nil)
- public static var startPage: Int?
+ public var startPage: Int?
@UserDefaultWrapper(key: Constants.user.rawValue, defaultValue: nil)
- public static var userInfo: UserInfo?
+ public var userInfo: UserInfo?
@UserDefaultWrapper(key: Constants.appPermissionChecked.rawValue, defaultValue: nil)
- public static var appPermissionChecked: Bool?
+ public var appPermissionChecked: Bool?
@UserDefaultWrapper(key: Constants.ignoredPopupIDs.rawValue, defaultValue: nil)
- public static var ignoredPopupIDs: [Int]?
+ public var ignoredPopupIDs: [Int]?
@UserDefaultWrapper(key: Constants.readNoticeIDs.rawValue, defaultValue: nil)
- public static var readNoticeIDs: [Int]?
+ public var readNoticeIDs: [Int]?
@UserDefaultWrapper(key: Constants.pushNotificationAuthorizationStatus.rawValue, defaultValue: nil)
- public static var pushNotificationAuthorizationStatus: Bool?
+ public var pushNotificationAuthorizationStatus: Bool?
@UserDefaultWrapper(key: Constants.songPlayPlatformType.rawValue, defaultValue: YoutubePlayType.youtube)
- public static var songPlayPlatformType: YoutubePlayType?
+ public var songPlayPlatformType: YoutubePlayType?
}
+/// BehaviorSubject๊ฐ Sendable์ ์ฑํํ์ง ์์ @unchecked
@propertyWrapper
-public final class UserDefaultWrapper {
+public final class UserDefaultWrapper: @unchecked Sendable {
+ private let lock = NSLock()
private let key: String
private let defaultValue: T?
+ private let subject: BehaviorSubject
init(key: String, defaultValue: T?) {
self.key = key
self.defaultValue = defaultValue
+
+ let initialValue: T?
+ if let savedData = UserDefaults.standard.object(forKey: key) as? Data {
+ let decoder = JSONDecoder()
+ if let lodedObejct = try? decoder.decode(T.self, from: savedData) {
+ initialValue = lodedObejct
+ } else {
+ initialValue = nil
+ }
+
+ } else if UserDefaults.standard.array(forKey: key) != nil {
+ initialValue = UserDefaults.standard.array(forKey: key) as? T
+ } else {
+ initialValue = defaultValue
+ }
+ self.subject = .init(value: initialValue)
}
public var wrappedValue: T? {
@@ -82,7 +101,6 @@ public final class UserDefaultWrapper {
}
}
- private lazy var subject = BehaviorSubject(value: wrappedValue)
public var projectedValue: Observable {
return subject.asObservable()
}
diff --git a/Projects/Modules/Utility/Sources/Manager/UserInfoManager.swift b/Projects/Modules/Utility/Sources/Manager/UserInfoManager.swift
index ec3b9a44f..1b9f3561b 100644
--- a/Projects/Modules/Utility/Sources/Manager/UserInfoManager.swift
+++ b/Projects/Modules/Utility/Sources/Manager/UserInfoManager.swift
@@ -8,7 +8,7 @@
import Foundation
-public struct UserInfo: Codable, Equatable {
+public struct UserInfo: Codable, Equatable, Sendable {
public let ID: String
public let platform: String
public let profile: String
diff --git a/Projects/Modules/Utility/Sources/Player/WakmusicPlayer.swift b/Projects/Modules/Utility/Sources/Player/WakmusicPlayer.swift
index 7963e92a5..331ba4caf 100644
--- a/Projects/Modules/Utility/Sources/Player/WakmusicPlayer.swift
+++ b/Projects/Modules/Utility/Sources/Player/WakmusicPlayer.swift
@@ -1,3 +1,4 @@
-public protocol WakmusicPlayer {
+@MainActor
+public protocol WakmusicPlayer: Sendable {
func play()
}
diff --git a/Projects/Modules/Utility/Sources/Player/WakmusicYoutubePlayer.swift b/Projects/Modules/Utility/Sources/Player/WakmusicYoutubePlayer.swift
index bbe42c8d2..ce2962c77 100644
--- a/Projects/Modules/Utility/Sources/Player/WakmusicYoutubePlayer.swift
+++ b/Projects/Modules/Utility/Sources/Player/WakmusicYoutubePlayer.swift
@@ -1,8 +1,9 @@
import Foundation
-import LinkPresentation
+@preconcurrency import LinkPresentation
import UIKit
-public struct WakmusicYoutubePlayer: WakmusicPlayer {
+@MainActor
+public struct WakmusicYoutubePlayer: WakmusicPlayer, Sendable {
fileprivate enum OpenerPlatform {
case youtube
case youtubeMusic
@@ -59,6 +60,7 @@ public struct WakmusicYoutubePlayer: WakmusicPlayer {
self.youtubeURLGenerator = youtubeURLGenerator
}
+ @MainActor
public func play() {
switch youtubeVideoType {
case let .videos(ids):
@@ -209,7 +211,7 @@ private extension WakmusicYoutubePlayer.PlayPlatform {
switch self {
case .youtube: return .youtube
case .youtubeMusic: return .youtubeMusic
- case .automatic: return PreferenceManager.songPlayPlatformType?.toOpnerPlatform ?? .youtube
+ case .automatic: return PreferenceManager.shared.songPlayPlatformType?.toOpnerPlatform ?? .youtube
}
}
}
diff --git a/Projects/Modules/Utility/Sources/Protocols/ContainerViewType.swift b/Projects/Modules/Utility/Sources/Protocols/ContainerViewType.swift
index f77415e25..00a99af78 100644
--- a/Projects/Modules/Utility/Sources/Protocols/ContainerViewType.swift
+++ b/Projects/Modules/Utility/Sources/Protocols/ContainerViewType.swift
@@ -10,10 +10,12 @@ import Foundation
import SnapKit
import UIKit
+// FIXME: concurrency๋ฅผ ์ํด mutable ํ๋กํผํฐ ๋ฆฌํฉํ ๋ง ํ์ ใ
ใ
ใ
public protocol ContainerViewType {
var contentView: UIView! { get set }
}
+@MainActor
public extension ContainerViewType where Self: UIViewController {
func add(asChildViewController viewController: UIViewController?) {
guard let viewController = viewController else {
diff --git a/Projects/Modules/Utility/Sources/Protocols/ViewControllerFromStoryBoard.swift b/Projects/Modules/Utility/Sources/Protocols/ViewControllerFromStoryBoard.swift
index 0d2cc9e14..3892a9966 100644
--- a/Projects/Modules/Utility/Sources/Protocols/ViewControllerFromStoryBoard.swift
+++ b/Projects/Modules/Utility/Sources/Protocols/ViewControllerFromStoryBoard.swift
@@ -12,6 +12,7 @@ import UIKit
public protocol ViewControllerFromStoryBoard {}
public protocol ViewControllerFromStoryBoardAndNeedle {}
+@MainActor
public extension ViewControllerFromStoryBoard where Self: UIViewController {
/// ์คํ ๋ฆฌ ๋ณด๋์ ์ ์๋ ํ๋ฉด์ ๊ฐ์ฒดํ ํ์ฌ ๋ฐํํฉ๋๋ค.
/// where Self: UIViewController: UIViewController์ ํ์ ํ์ฌ ์ฌ์ฉ
diff --git a/Projects/Modules/Utility/Sources/Realm/RealmManager.swift b/Projects/Modules/Utility/Sources/Realm/RealmManager.swift
index c108fd353..e659bda3a 100644
--- a/Projects/Modules/Utility/Sources/Realm/RealmManager.swift
+++ b/Projects/Modules/Utility/Sources/Realm/RealmManager.swift
@@ -22,9 +22,10 @@ import RealmSwift
- ์ฌ์๋ชฉ๋ก ์ ์ฅ์ ์ํ ์ํฐํฐ (๋ฆฌํฉํ ๋ง ๋ฒ์ )
- ๊ธฐ์กด PlayedList๋ ๋ ๊ฑฐ์๋ก ํ์ ํ์ฌ migration ๊ณผ์ ์์ ๋ฐ์ดํฐ ๋ชจ๋ ์ ๊ฑฐ
*/
-public class RealmManager: NSObject {
+/// Realm์ด Sendable์ ์ฑํํ์ง ์์์ @unchecked ํ์
+public class RealmManager: NSObject, @unchecked Sendable {
public static let shared = RealmManager()
- private var realm: Realm!
+ private let realm: Realm
override init() {
let config = Realm.Configuration(
diff --git a/Projects/Modules/Utility/Sources/Utils/Utils.swift b/Projects/Modules/Utility/Sources/Utils/Utils.swift
index 6c6e9890b..3ec317573 100644
--- a/Projects/Modules/Utility/Sources/Utils/Utils.swift
+++ b/Projects/Modules/Utility/Sources/Utils/Utils.swift
@@ -9,11 +9,13 @@
import Foundation
import UIKit
+@MainActor
public func APP_WIDTH() -> CGFloat {
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
return windowScene?.screen.bounds.size.width ?? .zero
}
+@MainActor
public func APP_HEIGHT() -> CGFloat {
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
return windowScene?.screen.bounds.size.height ?? .zero
@@ -23,6 +25,7 @@ public func PLAYER_HEIGHT() -> CGFloat {
return 56.0
}
+@MainActor
public func STATUS_BAR_HEGHIT() -> CGFloat {
return UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
@@ -33,6 +36,7 @@ public func STATUS_BAR_HEGHIT() -> CGFloat {
.top ?? 0
}
+@MainActor
public func SAFEAREA_BOTTOM_HEIGHT() -> CGFloat {
return UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
@@ -51,6 +55,7 @@ public func APP_NAME() -> String {
return Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? ""
}
+@MainActor
public func OS_VERSION() -> String {
return UIDevice.current.systemVersion
}
diff --git a/Projects/Modules/Utility/Sources/Youtube/YoutubeURLGenerator.swift b/Projects/Modules/Utility/Sources/Youtube/YoutubeURLGenerator.swift
index ab0ab8927..021b0f771 100644
--- a/Projects/Modules/Utility/Sources/Youtube/YoutubeURLGenerator.swift
+++ b/Projects/Modules/Utility/Sources/Youtube/YoutubeURLGenerator.swift
@@ -1,6 +1,6 @@
import Foundation
-public protocol YoutubeURLGeneratable {
+public protocol YoutubeURLGeneratable: Sendable {
func generateThumbnailURL(id: String) -> String
func generateHDThumbnailURL(id: String) -> String
func generateYoutubeVideoAppURL(id: String) -> String
@@ -16,7 +16,7 @@ public protocol YoutubeURLGeneratable {
func generateYoutubeMusicPlaylistWebURL(id: String) -> String
}
-public struct YoutubeURLGenerator: YoutubeURLGeneratable {
+public struct YoutubeURLGenerator: YoutubeURLGeneratable, Sendable {
public init() {}
// MARK: Youtube
diff --git a/Projects/UsertInterfaces/DesignSystem/Sources/LikeButton.swift b/Projects/UsertInterfaces/DesignSystem/Sources/LikeButton.swift
index cf68a824e..a62dbd079 100644
--- a/Projects/UsertInterfaces/DesignSystem/Sources/LikeButton.swift
+++ b/Projects/UsertInterfaces/DesignSystem/Sources/LikeButton.swift
@@ -9,11 +9,7 @@
import DesignSystem
import UIKit
-protocol Likeable {
- var isLiked: Bool { get set }
-}
-
-class LikeButton: VerticalImageButton, Likeable {
+class LikeButton: VerticalImageButton {
var isLiked: Bool = false {
didSet {
setColor()
diff --git a/Projects/UsertInterfaces/DesignSystem/Sources/SingleActionButtonView.swift b/Projects/UsertInterfaces/DesignSystem/Sources/SingleActionButtonView.swift
index 6e1aeed11..835d7b426 100644
--- a/Projects/UsertInterfaces/DesignSystem/Sources/SingleActionButtonView.swift
+++ b/Projects/UsertInterfaces/DesignSystem/Sources/SingleActionButtonView.swift
@@ -2,6 +2,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
public protocol SingleActionButtonViewDelegate: AnyObject {
func tappedButtonAction()
}
diff --git a/Projects/UsertInterfaces/DesignSystem/Sources/VerticalAlignButton.swift b/Projects/UsertInterfaces/DesignSystem/Sources/VerticalAlignButton.swift
index 81d13eb9f..c862645d3 100644
--- a/Projects/UsertInterfaces/DesignSystem/Sources/VerticalAlignButton.swift
+++ b/Projects/UsertInterfaces/DesignSystem/Sources/VerticalAlignButton.swift
@@ -33,11 +33,6 @@ open class VerticalAlignButton: UIButton {
fatalError("init(coder:) has not been implemented")
}
- override open func awakeFromNib() {
- super.awakeFromNib()
- self.contentHorizontalAlignment = .left
- }
-
public func setTextColor(color: UIColor) {
self.configuration?.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer {
var attribute = $0
diff --git a/Projects/UsertInterfaces/DesignSystem/Sources/WMNavigationBarView.swift b/Projects/UsertInterfaces/DesignSystem/Sources/WMNavigationBarView.swift
index a455f6462..012e95e14 100644
--- a/Projects/UsertInterfaces/DesignSystem/Sources/WMNavigationBarView.swift
+++ b/Projects/UsertInterfaces/DesignSystem/Sources/WMNavigationBarView.swift
@@ -2,6 +2,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
public final class WMNavigationBarView: UIView {
private let leftStackView = UIStackView().then {
$0.axis = .horizontal
@@ -65,7 +66,7 @@ public final class WMNavigationBarView: UIView {
$0.removeFromSuperview()
rightStackView.removeArrangedSubview($0)
}
- views.forEach(rightStackView.addArrangedSubview(_:))
+ views.forEach { rightStackView.addArrangedSubview($0) }
}
public func setLeftViews(_ views: [UIView]) {
@@ -73,7 +74,7 @@ public final class WMNavigationBarView: UIView {
$0.removeFromSuperview()
leftStackView.removeArrangedSubview($0)
}
- views.forEach(leftStackView.addArrangedSubview(_:))
+ views.forEach { leftStackView.addArrangedSubview($0) }
}
}
diff --git a/Projects/UsertInterfaces/DesignSystem/Sources/WMRetryWarningView.swift b/Projects/UsertInterfaces/DesignSystem/Sources/WMRetryWarningView.swift
index fbaf43b6a..3275bed70 100644
--- a/Projects/UsertInterfaces/DesignSystem/Sources/WMRetryWarningView.swift
+++ b/Projects/UsertInterfaces/DesignSystem/Sources/WMRetryWarningView.swift
@@ -3,6 +3,7 @@ import SnapKit
import Then
import UIKit
+@MainActor
public protocol WMRetryWarningViewDelegate: AnyObject {
func tappedRetryButton()
}
diff --git a/Tuist/ProjectDescriptionHelpers/GenerateEnvironment.swift b/Tuist/ProjectDescriptionHelpers/GenerateEnvironment.swift
index 306c1dfa2..963b626e9 100644
--- a/Tuist/ProjectDescriptionHelpers/GenerateEnvironment.swift
+++ b/Tuist/ProjectDescriptionHelpers/GenerateEnvironment.swift
@@ -21,7 +21,7 @@ public extension GenerateEnvironment {
return [.firebaseInfoByConfiguration, .firebaseCrashlytics]
case .dev:
- return [.swiftLint, .needle]
+ return [.swiftLint]
}
}
}