[λμμΈ ν¨ν΄] μ±κΈν€ ν¨ν΄μ΄λ? (iOS - Singleton Design Pattern) + μμ‘΄μ± μ£Όμ
(DI)
2022. 12. 24. 19:36γComputerScience/DesignPattern
β μ±κΈν€ ν¨ν΄ (Singleton Pattern)
- νλμ ν΄λμ€μ νλμ μΈμ€ν΄μ€λ§ κ°μ§λ ν¨ν΄
- λ°μ΄ν°λ² μ΄μ€ μ°κ²° λͺ¨λμ λ§μ΄ μ¬μ©λ¨
- iOS μμλ λ§μ΄ μ μ©λλ μ€μν λμμΈ ν¨ν΄ μ€ νλ
- μ¬λ¬ νμΌμμ λμΌν κ°μ²΄λ₯Ό νμ©ν΄μΌ νλ κ²½μ°, μ±κΈν€ ν¨ν΄μ λ μ¬λ¦¬μ
- μ±κΈν€ ν¨ν΄ -> κ°μ²΄κ° μμ±λλ©΄ μμλ‘ λ©λͺ¨λ¦¬μμ ν΄μ νμ§ μλ μ΄μ νλ‘κ·Έλ¨μ΄ λλ λκΉμ§ λ©λͺ¨λ¦¬μ μ μ§λ¨
- νλ‘μ νΈ λ΄μμ κ°μ²΄λ₯Ό νλλ§ μμ±νμ¬ κ³΅μ©μΌλ‘ μ¬μ©νλ κ²½μ° νμ©
// Shared URL Session
let sharedURLSession = URLSession.shared
// Default File Manager
let defaultFileManager = FileManager.default
// Standard User Defaults
let standardUserDefaults = UserDefaults.standard
// Default Payment Queue
let defaultPaymentQueue = SKPaymentQueue.default()
let screen = UIScreen.main
let useDefault = UserDefaults.standard
let application = UIApplication.shared
let fileManager = FileManager.default
let notification = NotificationCenter.default
# νλ‘μ νΈμμ νμ©ν μμ μ½λλ€
# TARS - SPACEOVER: https://github.com/DeveloperAcademy-POSTECH/MacC-Team-TARS
class LocationManager: NSObject, CLLocationManagerDelegate {
static let shared = LocationManager()
weak var delegate: LocationManagerDelegate?
private let locationManager = CLLocationManager()
private var location: CLLocation?
private var isLocationUpdated: Bool = false
override init() {
super.init()
locationManager.delegate = self
}
class AudioManager {
static let shared = AudioManager()
var audioPlayer: AVAudioPlayer?
init() {}
Hint - static let shared
μ±κΈν€ ν¨ν΄μ μ₯λ¨μ
- νλμ μΈμ€ν΄μ€λ₯Ό μμ±νμ¬ κ³΅μ -> μμ± λΉμ©μ΄ μ€μ΄λ λ€
- But μμ‘΄μ±μ΄ λμμ§λ€λ λ¨μ
- TDD (Test Driven Development) ν
μ€νΈ μ£Όλ κ°λ° μ λ¬Έμ
- λ¨μ ν μ€νΈ - ν μ€νΈκ° μλ‘ λ 립μ μ΄μ΄μΌ νλ€.
- νλμ μΈμ€ν΄μ€λ₯Ό κΈ°λ°μΌλ‘ ꡬν -> ν μ€νΈλ§λ€ λ 립μ μΈ μΈμ€ν΄μ€ μμ±μ΄ μ΄λ ΅λ€
- μμ‘΄μ± μ£Όμ
(DI, Dependency Injection)
- μ±κΈν€ ν¨ν΄μ μ½κ³ μ€μ©μ μ΄λ, λͺ¨λ κ°μ κ²°ν©μ κ°νκ² νλ€.
- μμ‘΄μ± μ£Όμ μ ν΅ν΄ λͺ¨λ κ°μ κ²°ν©μ λμ¨νκ² λ§λ€μ΄ ν΄κ²°ν μ μλ€.
- λ©μΈ λͺ¨λ -> μμ‘΄μ± μ£Όμ μκ° κ°λ‘μ± -> λ©μΈ λͺ¨λμ νμ λͺ¨λμ λν μμ‘΄μ±μ΄ λ¨μ΄μ§κ² λλ€ (λ컀νλ§ λλ€)
- μμ‘΄μ± μ£Όμ μμΉ: μμ λͺ¨λμ νμ λͺ¨λμμ μ΄λ ν κ²λ κ°μ Έμ€μ§ μμμΌ νλ€ / λ λ€ μΆμν μμΉμ μμ‘΄ν΄μΌ νλ©°, μ΄λ μΆμνλ μΈλΆ μ¬νμ μμ‘΄νμ§ λ§μμΌ νλ€.
- TDD (Test Driven Development) ν
μ€νΈ μ£Όλ κ°λ° μ λ¬Έμ
μμ‘΄μ± μ£Όμ μ λν΄ λ μμ보기
- Dependency Injection means giving an objects its instance variable. Really. That's it - James Shore
- μμ‘΄μ± μ£Όμ μ΄λ, κ°μ²΄ κ° κ²°ν©μ λμ¨νκ² νκΈ° μνμ¬, νΉμ κ°μ²΄μ μμ±μ μμ μ΄ μλ λ€λ₯Έ κ°μ²΄κ° μ΄κΈ°ννλ κ²
- λμ¨ν κ²°ν© -> μ£Όμ λ°λ μμ±μ νμ μ νλ‘ν μ½λ‘ μμ± -> ν μ€νΈκ° μ©μ΄ν΄μ§κ³ , μλκ° λͺ νν μ½λ
- μμ‘΄ κ΄κ³λ ν ν΄λμ€κ° λ€λ₯Έ ν΄λμ€μμ μ 곡νλ κΈ°λ₯μ μ¬μ©ν λ λ°μ !
- νλ‘ν μ½ νμ© - λͺ¨λ κΈ°λ₯μ΄ μλλΌ, νμν μ νλ κΈ°λ₯λ§μ μ 곡λ°μ μ μμ΄ λΆνμν μ½λ νμ₯μ΄ μμ΄μ§
- μμ‘΄μ± μ£Όμ
μ μ₯μ : μ±
μμ΄ μ’ λ λͺ
νν΄μ§ ν΄λμ€λ₯Ό μ»μ μ μλ€. μ΄λ€ μμ‘΄ κ΄κ³μ μꡬμ¬νμ΄ μλμ§ μμνκ² νμΈ κ°λ₯
Testable ν ν΄λμ€λ₯Ό μ»κ² λλ€. Protocol typeμΌλ‘ λ°μ μ μ½κ² Mock μ€λΈμ νΈλ‘ λ체ν μ μκΈ° λλ¬Έ
κ΄μ¬μ¬μ λΆλ¦¬ μμΉμ μ μ§ν¬ μ μλ€ -> λ μ΄μ μμ‘΄ κ΄κ³μ κ°μ²΄μ μ΄κΈ°νμ μ§μ κ΄μ¬ν νμκ° μμ
νλ‘ν μ½μ μ¬μ©ν μμ‘΄μ± μ£Όμ -> κ²°ν©λλ₯Ό μ€μ΄κ³ , μ£Όμ λ κ°μ²΄μ μ± μμ λͺ νν ν μ μλ€ - Do not depend on Concretion, Depend on Abstraction
# μ±κΈν€ ν¨ν΄
import StreamChat
import UIKit
/// 1: Extend the `ChatClient` class.
extension ChatClient {
/// 2: Add a `shared` static variable of its own type.
static var shared: ChatClient!
}
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
/// 3: Create a `Token` and `TokenProvider`.
let token = Token("[jwt token]")
let tokenProvider = TokenProvider.static(token)
/// 4: Create a `ChatClientConfig` with the API key.
let config = ChatClientConfig(apiKeyString: "[api_key]")
/// 5: Set the shared `ChatClient` instance with the config and the token provider.
ChatClient.shared = ChatClient(config: config, tokenProvider: tokenProvider)
return true
}
}
# μμ μ½λμ μμ‘΄μ± μ£Όμ DI μ μ©
import StreamChat
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let scene = (scene as? UIWindowScene) else { return }
/// 1: Get the reference to the initial view controller
let viewController = window?.rootViewController as? ViewController
/// 2: Create a `ChatClientConfig` with the API key.
let config = ChatClientConfig(apiKeyString: "[api_key]")
/// 3: Create a `ChatClient` instance with the config and the tokenProvider.
let chatClient = ChatClient(config: config, tokenProvider: tokenProvider)
/// 4: Inject the `ChatClient` object into your `ViewController`.
viewController?.chatClient = chatClient
}
}
μ±κΈν€ ν¨ν΄μ μ¬μ© μμ
- Node.js μμ MongoDB μ°κ²°μ νμ©νλ mongoose λͺ¨λ
- Node.js μμ MySQL μ°κ²°μμλ μ±κΈν€ ν¨ν΄μ΄ μ¬μ©λ¨
- iOS μ½λ ꡬμꡬμ μ λ§ λ§μ΄ μ¬μ©λ¨ (μμ μμλ€)
μΆμ²
- λ©΄μ μ μν CS μ 곡μ§μλ ΈνΈ - μ£Όνμ²
- https://woozzang.tistory.com/137
- https://velog.io/@sso0022/iOS-Singleton-Pattern
- https://getstream.io/blog/singleton-dependency-injection-in-swift/
- https://jiseok-zip.tistory.com/entry/iOSμ±κΈν€-ν¨ν΄Singleton-Pattern