Weekoding

[Swift] Singleton pattern(싱글톤 패턴) 본문

공부 노트(Swift)

[Swift] Singleton pattern(싱글톤 패턴)

Weekoding 2023. 3. 6. 01:16

궁금증이 생겨 싱글톤 패턴을 Swift에서 어떻게 구현하는지 알아보려고 한다.

이 포스팅은 싱글톤 패턴에 대한 기본적인 지식은 전제로 하여 개념은 최대한 간단히 짚고

구현 방법도 같이 알아볼 것이다.

 

 

 

📂  Singleton Pattern?

: 최초 한 번만 메모리를 할당(static)하고, 해당 메모리에 인스턴스를 생성하여 사용하는 패턴.

  즉 ,하나의 인스턴스만 존재한다. 이후 각각의 클래스에서 하나의 인스턴스에 접근이 가능하다.

  Singleton
장점 • 메모리 낭비를 방지할 수 있다.(한 개의 인스턴스만 생성하므로)
• 전역 인스턴스이기 때문에 다른 클래스간 공유가 쉬움
• 인스턴스가 절대적으로 하나만 있음을 보증해야 할 때 유용함
• 두 번째 이용부터는 로딩 시간이 현저하게 줄어들어 효율 면에서 뛰어남
• 공통 객체를 여러개 생성해야하는 경우(DBCP-DataBase Connection Pool-등) 유용하게 사용될 수 있음
  → 쓰레드풀, 캐시, 대화상자, 사용자 설정, 레지스트리 설정, 로그 기록 객체 등
단점 • 싱글톤 인스턴스가 너무 많은 일/데이터를 가지게 되면 다른 클래스의 인스턴스간 결합도가 높아짐
   (객체 지향 설계 원칙인 '개방-폐쇄 원칙 '을 위배)
• 위 '개방-폐쇄' 원칙을 위배할 시, 수정 및 테스트가 어려워짐
• '동시성(Thread-safe)문제 ' 가 발생할 수 있음

개방-폐쇄 원칙의 위배 : 의존도가 너무 높아지게 된다면, 해당 싱글톤 인스턴스를 수정했을 경우

다른 싱글톤 인스턴스를 사용하는 곳에서 사이드 이펙트가 발생할 수 있다는 의미이다.

동시성(Thread-safe) 문제 : Multi-Thread 환경에서 인스턴스가 2개 이상 생길 수 있는 문제를 의미한다.

 

 

 

📂  Singleton Pattern in Swift

'Multi-Thread' 환경에서 Thread-Safe하지 않다는 특징 때문에,

기존에는 특정 키워드를 통해 Application의 실행 이후 단 한번만 코드가 실행될 수 있도록 설정해 주어야 했다.

java - LazyHolder  /  Objc - dispatch_once

 

그러나 Swift는 별도의 작업이 필요 없다.

'static let' property에 인스턴스를 생성하면, lazy variable와 비슷하게 최초 생성되기 전까지 메모리에 올라가지 않는다.

또한 GCD(Grand Central Dispatch)dispatch_once도 자동으로 적용된다.

💫  헷갈리는 부분 정리 💫

static let = 한번 초기화되면 변경되지 않는 정적 변수
lazy var = 초기화가 필요한 경우에만 초기화 되는 변수

static letlazy var 모두 처음 접근될 때 초기화된다는 공통점이 있지만, 차이점은 초기화 시점에 있다.

static let은 프로그램 시작 시점에 초기화된다.
이는 애플리케이션 실행 중에 해당 객체에 처음 접근하기 전에 초기화된다는 의미이다.

반면 lazy var는 해당 객체에 처음 접근할 때 초기화된다.
이는 애플리케이션 실행 중에 해당 객체를 사용하기 전까지는 초기화되지 않는다는 의미이다.

따라서, static let 애플리케이션 실행 시 초기화가 보장된다. 그래서 Singleton 인스턴스 생성에 사용되는 것이다.
하지만 lazy var은 초기화 시점이 해당 객체에 접근될 때까지 늦춰질 수 있기 때문에, 의도치 않은 결과를 가져올 수 있다.

 

따라서 Swift는 추가적인 조치 없이도 Thread-Safe한 방법으로 Singleton 인스턴스를 생성할 수 있다.

 

추가로, iOS는 Singleton 인스턴스를 대표적으로 아래와 같은 곳에서 사용하고 있다.

UIScreen.main
UserDefaults.standard
UIApplication.shared
FileManager.default
NotificationCenter.default

개인적으로는 UIScreen.main, UserDefaults.standard가 아주 친숙하다 !

 

 

 

📂  How to make Singleton Pattern in Swift?

앞서 보았듯 'static let' 키워드가 아주 중요하며, 방법은 아주 간단하다. 예시 코드는 아래와 같다.

// 1. static let 프로퍼티에 Singleton 인스턴스로 사용할 인스턴스를 저장해준다.
// 2. init 함수를 'private'로 선언하여, 다른 클래스에서 접근하지 못하도록 한다.(인스턴스 생성 방지)

class FamilyCar {
    static let shared = FamilyCar()
    private init() { }
    
    var trunk_luggage: String?
    var gasoline: Float?
    var currentState_Using: Bool?
}

가족 구성원이 공용으로 사용하는 차 정보를 갖는 Singleton 인스턴스가 간단히 완성되었다.

 

//Father Class
let familyCar = familyCar.shared
familyCar.currentState_using = false //아빠 퇴근했다~
//Daughter Class
let familyCar = familyCar.shared
familyCar.currentState_using = true
familyCar.gasoline = 100.0 //기름 만땅 채워놨습니다~

FamilyCar 인스턴스의 static let property인 'shared'를 이용하여, 온 가족이 즐겁게 자동차를 공유할 수 있게 되었다.

 

 

 

 

📌 마치며

공통된 데이터에 접근할 수 있다는 것은 분명히도 편리한 점이다. 그러나 남용은 언제나 좋지 않은 법이다.

적재적소에 사용할 줄 알아야 하고, 객체지향 프로그래밍에서 의존성을 낮추는 것이 아주 중요한 점이기 떄문에

Singleton Pattern이 과연 최선인지를 의심해보는 자세가 필요한 것 같다.

 

 

 

오류 및 지적사항은 댓글로 남겨주시면 감사하겠습니다!

참고 : 

https://babbab2.tistory.com/66

Comments