[Swift] 싱글톤 패턴(Singleton Pattern)이란?

toma·2022년 9월 6일
1
post-thumbnail

싱글톤 패턴(Singleton Pattern)이란?

GOF 패턴의 생성 패턴 중 하나로 특정 용도로 객체를 하나만 생성한 뒤, 공용으로 사용하고 싶을 때 사용하는 디자인 패턴

즉, 인스턴스가 하나만 존재하는 것을 보증하고 싶을 경우에 사용합니다.

쉽게 말해서 클래스에 대한 Instance는 최초 생성될 때 딱 한번만 생성해서 전역에 두고, 그 이후로는 이 Instance만 접근 가능하게 하는 방법이 바로 싱글톤 패턴이에요.

주로 환경설정네트워크 객체로그인 정보등을 특정 용도로 생성해둔 객체에 넣어두고 필요할 때마다 여러 객체에서 접근 가능하도록 하여 데이터를 사용합니다.

🍎iOS에서 자주 사용되는 싱글톤 패턴

let sreen = UIScreen.main
let userDefaults = UserDefaults.standard
let application = UIApplication.shared
let fileManager = FileManager.default
let notification = NotificationCenter.default

iOS개발 할 때 자주 사용하는 싱글톤 패턴들입니다!

🔉 예시

그렇다면 이제 전역에서 Sound를 관리하는 용도의 싱글톤, SoundManager를 한번 생성해봅시다!

프로젝트 특성상 Sound에 접근해야 하는 경우가 잦은데 매번 Play할 때마다 AVAudioPlayer 객체를 생성해 관리하는 것보다는, 싱글톤으로 필요할 때마다 Sound Resource만 바꾸어 play하는 것이 효율적이라고 판단했어요.


final class SoundManager {
  static let shared = SoundManager()
  private var soundEffect: AVAudioPlayer?
  var soundType: SoundType?
  
  private init() { }  
}

싱글톤의 기본적인 형태예요.

  • 하나의 인스턴스를 공유하기위해 static let으로 인스턴스 선언
  • 다른 곳에서 init을 호출하지 못하도록 private으로 선언

그리고 클래스 내부에 필요한 함수들을 추가해줍니다.

  func playSound(loops: Int = 0) { // enumCase에 따른 사운드 재생
    var withExtension: String
    
    switch soundType {
    case .splash:
      withExtension = "wav"
    default:
      withExtension = "mp3"
    }
    
    guard let url = Bundle.main.url(forResource: soundType?.rawValue, withExtension: withExtension)  else { return }
    
    do {
      soundEffect = try AVAudioPlayer(contentsOf: url)
      soundEffect?.numberOfLoops = loops
      soundEffect?.play()
    } catch let error {
      print(error.localizedDescription)
    }
    
  }
  
  func setVolumeFadeIn(duration: TimeInterval = 2) { // 사운드 페이드인
    soundEffect?.setVolume(0, fadeDuration: duration)
  }
  
  func setVolumeFadeOut(duration: TimeInterval = 2) { // 사운드 페이드 아웃
    soundEffect?.setVolume(1, fadeDuration: duration)
  }
  
  func playStoppedSound() { // 중지된 사운드 재생
    soundEffect?.play()
  }
  
  func stopSound() { // 사운드 중지
    soundEffect?.stop()
  }

이렇게 작성하면

SoundManager.shared.soundType = .main
SoundManager.shared.playSound()

이렇게 soundType에 따라 sound를 조작할 수 있는 싱글톤이 완성됩니다.


👍 싱글톤의 장점

  • 하나의 인스턴스만 사용하므로 메모리 낭비를 방지할 수 있습니다.
  • 전역 인스턴스쉽게 데이터를 공유할 수 있습니다.

👎 싱글톤의 단점

싱글톤은 안티 패턴?

  • 싱글톤 인스턴스가 너무 많은 일을 하거나, 많은 데이터를 공유시킬 경우 다른 클래스의 Instance들 간 결합도가 높아져 개방-폐쇄 원칙을 위배
    (객체 지향 설계 원칙에 어긋남)
  • 이니셜라이저를 통해서 의존성 주입을 하지 못해서, test doubles를 통한 테스트가 어렵습니다.

🤔 Thread Safe?

Thread Safe란 여러 스레드에서 어떤 객체에 대해 동시에 접근이 이루어져도 프로그램의 동작에 이상이 없는 것을 뜻합니다.

만약 멀티 스레드 환경에서 동시에 싱글톤을 사용하는 경우 인스턴스가 2개 이상 생성되는 Thread Unsafe한 경우가 생길 수 있습니다!

이를 방지하고자 Objective-C에서는 dispatch_once_t 를 사용하여 인스턴스가 1회만 생성된다는 것을 보장합니다.

하지만 swift는 static let으로 선언하는 것만으로도 1회 생성을 보장한다고 합니다!
아주 간편하군요! 그러나 싱글톤은 앞서 말했듯이 안티 패턴이라 불릴 정도로 단점도 가지고 있기에 적절한 상황에서 사용하면 좋을 것 같습니다.

참고

[iOS, swift] thread-safety 한 싱글톤 사용은?
[swift]싱글톤 패턴

profile
Don't think, just do 🎸

0개의 댓글