Skip to content
12 changes: 9 additions & 3 deletions Projects/App/Sources/DI/Assembly/DataAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import Swinject
public class DataAssembly: Assembly {
public func assemble(container: Swinject.Container) {
// MARK: Servcie
container.register(UserConfigurationService.self) { _ in
DefaultUserConfigurationService()
container.register(KeyValueStoreService.self) { _ in
DefaultKeyValueStoreService()
}
.inObjectScope(.container)

container.register(WebSocketService.self) { _ in
BinanceWebSocketService()
Expand All @@ -36,6 +37,12 @@ public class DataAssembly: Assembly {


// MARK: DataSource
container.register(UserConfigurationDataSource.self) { resolver in
DefaultUserConfigurationDataSource(
service: resolver.resolve(KeyValueStoreService.self)!
)
}
.inObjectScope(.container)
container.register(CoinTradeDataSource.self) { _ in
BinanceCoinTradeDataSource()
}
Expand All @@ -52,7 +59,6 @@ public class DataAssembly: Assembly {
container.register(UserConfigurationRepository.self) { _ in
DefaultUserConfigurationRepository()
}
.inObjectScope(.container)

container.register(AllMarketTickersRepository.self) { _ in
BinanceAllMarketTickersRepository()
Expand Down
6 changes: 6 additions & 0 deletions Projects/App/Sources/DI/Assembly/DomainAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ class DomainAssembly: Assembly {

func assemble(container: Swinject.Container) {
// UseCase
container.register(SettingPageUseCase.self) { resolver in
DefaultSettingPageUseCase(
repository: resolver.resolve(UserConfigurationRepository.self)!
)
}

container.register(RootPageUseCase.self) { _ in
DefaultRootPageUseCase()
}
Expand Down
5 changes: 3 additions & 2 deletions Projects/App/Sources/DI/Assembly/SharedAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by choijunios on 12/4/24.
//

import DomainInterface
import DataSource

import WebSocketManagementHelper
Expand All @@ -28,8 +29,8 @@ public class SharedAssembly: Assembly {
.inObjectScope(.container)

//MARK: I18NManager
container.register(I18NManager.self) { _ in
DefaultI18NManager()
container.register(I18NManager.self) { resolver in
DefaultI18NManager(repository: resolver.resolve(UserConfigurationRepository.self)!)
}
.inObjectScope(.container)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// UserConfigurationDataSource.swift
// Data
//
// Created by choijunios on 5/4/25.
//

public protocol UserConfigurationDataSource {
func getCurrency() -> String?
func setCurrency(type: String)

func getLanguageType() -> String?
func setLanguageType(type: String)

func getGridType() -> String?
func setGridType(type: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// KeyValueStoreService.swift
// DataSource
//
// Created by choijunios on 10/15/24.
//

import Foundation

public protocol KeyValueStoreService {
func fetch(key: String) -> Any?
func save(key: String, value: Any)
}


public class DefaultKeyValueStoreService: KeyValueStoreService {
// Dependency
private let source: UserDefaults = .standard

public init() { }
}


// MARK: KeyValueStoreService
public extension DefaultKeyValueStoreService {
func fetch(key: String) -> Any? { source.object(forKey: key) }
func save(key: String, value: Any) { source.set(value, forKey: key) }
}
33 changes: 0 additions & 33 deletions Projects/Data/DataSource/Service/UserConfigurationService.swift

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// DefaultUserConfigurationDataSource.swift
// Data
//
// Created by choijunios on 5/4/25.
//

import CoreUtil

final public class DefaultUserConfigurationDataSource: UserConfigurationDataSource {
// Dependency
private var service: KeyValueStoreService

// State
private let memoryCache: LockedDictionary<String, Any> = .init()

// Keys
private let currencySavingKey = "configuration_currency"
private let languageSavingKey = "configuration_language"
private let gridTypeSavingKey = "configuration_gridType"


public init(service: KeyValueStoreService) {
self.service = service
}


private func checkMemCache<T>(key: String) -> T? { memoryCache[key] as? T }
private func cacheToMemory(key: String, value: Any) { memoryCache[key] = value }
private func fetch(key: String) -> Any? {
if let memoryCache: String = checkMemCache(key: key) {
// 매모리 캐쉬가 존재하는 경우
return memoryCache
}
if let storeData = service.fetch(key: key) {
// 로컬에 저장된 정보가 있는 경우
defer { cacheToMemory(key: key, value: storeData) }
return storeData
}
return nil
}
private func save(key: String, value: Any) {
service.save(key: key, value: value)
cacheToMemory(key: key, value: value)
}
}


// MARK: UserConfigurationDataSource
public extension DefaultUserConfigurationDataSource {
func getCurrency() -> String? { fetch(key: currencySavingKey) as? String }
func setCurrency(type: String) { save(key: currencySavingKey, value: type) }

func getLanguageType() -> String? { fetch(key: languageSavingKey) as? String }
func setLanguageType(type: String) { save(key: languageSavingKey, value: type) }

func getGridType() -> String? { fetch(key: gridTypeSavingKey) as? String }
func setGridType(type: String) { save(key: gridTypeSavingKey, value: type) }
}
1 change: 0 additions & 1 deletion Projects/Data/Repository/BinanceCoinTradeRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import CoreUtil

public final class BinanceCoinTradeRepository: CoinTradeRepository {
// Dependency
@Injected private var webSocketService: WebSocketService
@Injected private var coinTradeDataSource: CoinTradeDataSource

public init() { }
Expand Down
128 changes: 21 additions & 107 deletions Projects/Data/Repository/DefaultUserConfigurationRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,121 +13,35 @@ import CoreUtil

public class DefaultUserConfigurationRepository: UserConfigurationRepository {
// Dependency
@Injected var userConfigurationService: UserConfigurationService

// Cache configuration
private let cachedConfiguration: LockedDictionary<String, Any> = .init()
@Injected private var dataSource: UserConfigurationDataSource

public init() { }

public func getCurrencyType() -> CurrencyType {
let config: UserConfiguration = .currency

if let memoryCached: String = checkMemoryCache(key: config.savingKey) {
// 캐싱된 정보를 먼저 확인합니다.
return .init(rawValue: memoryCached)!
}

if let diskCached = userConfigurationService.getStringValue(key: config.savingKey) {
// 로컬에 저장된 정보를 확인합니다.

// 정보를 메모리에 캐싱
caching(key: config.savingKey, value: diskCached)

return .init(rawValue: diskCached)!
}

return .init(rawValue: config.defaultSavingValue)!
}



public func setCurrencyType(type: CurrencyType) {
let config: UserConfiguration = .currency

// 디스크 저장
userConfigurationService.setConfiguration(key: config.savingKey, value: type.savingValue)

// 정보를 메모리에 캐싱
caching(key: config.savingKey, value: type.savingValue)
}


public func getLanguageType() -> LanguageType {
let config: UserConfiguration = .language

if let memoryCached: String = checkMemoryCache(key: config.savingKey) {
// 캐싱된 정보를 먼저 확인합니다.
return .init(rawValue: memoryCached)!
}

if let diskCached = userConfigurationService.getStringValue(key: config.savingKey) {
// 로컬에 저장된 정보를 확인합니다.

// 정보를 메모리에 캐싱
caching(key: config.savingKey, value: diskCached)

return .init(rawValue: diskCached)!
}

return .init(rawValue: config.defaultSavingValue)!
}


// MARK: UserConfigurationRepository
public extension DefaultUserConfigurationRepository {
func getCurrencyType() -> CurrencyType? {
guard let value = dataSource.getCurrency() else { return nil }
return CurrencyType(rawValue: value)
}


public func setLanguageType(type: LanguageType) {
let config: UserConfiguration = .language

// 디스크 저장
userConfigurationService.setConfiguration(key: config.savingKey, value: type.savingValue)

// 메모리 저장
cachedConfiguration[config.savingKey] = type.savingValue
func setCurrencyType(type: CurrencyType) {
dataSource.setCurrency(type: type.rawValue)
}


public func getGridType() -> GridType {
let config: UserConfiguration = .gridType

if let memoryCached: String = checkMemoryCache(key: config.savingKey) {
// 캐싱된 정보를 먼저 확인합니다.
return .init(rawValue: memoryCached)!
}

if let diskCached = userConfigurationService.getStringValue(key: config.savingKey) {
// 로컬에 저장된 정보를 확인합니다.

// 정보를 메모리에 캐싱
caching(key: config.savingKey, value: diskCached)

return .init(rawValue: diskCached)!
}

return .init(rawValue: config.defaultSavingValue)!
func getLanguageType() -> LanguageType? {
guard let value = dataSource.getLanguageType() else { return nil }
return LanguageType(rawValue: value)
}



public func setGridType(type: GridType) {
let config: UserConfiguration = .gridType

// 디스크 저장
userConfigurationService.setConfiguration(key: config.savingKey, value: type.savingValue)

// 메모리 저장
cachedConfiguration[config.savingKey] = type.savingValue
func setLanguageType(type: LanguageType) {
dataSource.setLanguageType(type: type.rawValue)
}


// MARK: check cache
private func checkMemoryCache<T>(key: String) -> T? {
cachedConfiguration[key] as? T
func getGridType() -> GridType? {
guard let value = dataSource.getGridType() else { return nil }
return GridType(rawValue: value)
}

private func caching(key: String, value: Any) {

DispatchQueue.global().async { [weak self] in
// 정보를 메모리에 캐싱
self?.cachedConfiguration[key] = value
}
func setGridType(type: GridType) {
dataSource.setGridType(type: type.rawValue)
}
}
21 changes: 21 additions & 0 deletions Projects/Data/Tests/Testing/FakeKeyValueStoreService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// FakeKeyValueStoreService.swift
// Data
//
// Created by choijunios on 5/4/25.
//

import DataSource

final class FakeKeyValueStoreService: KeyValueStoreService {

private var fakeDB: [String: Any] = [:]

func fetch(key: String) -> Any? {
fakeDB[key]
}

func save(key: String, value: Any) {
fakeDB[key] = value
}
}
Loading