애플 공식문서에서는 다음과 같이 나와있습니다.
A singleton class returns the same instance no matter how many times an application requests it. A typical class permits callers to create as many instances of the class as they want, whereas with a singleton class, there can be only one instance of the class per process. A singleton object provides a global point of access to the resources of its class. Singletons are used in situations where this single point of control is desirable, such as with classes that offer some general service or resource.
출처: https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Singleton.html
해석을 해보겠습니다.
"싱글톤 클래스"는 같은 인스턴스를 반환합니다. 아무리 많이 앱에서 요청을 하더라도 같은 인스턴스를 반환합니다.
일반적인 클래스는 호출자가 원하는만큼 클래스의 인스턴스를 만들 수 있도록 허용하는 반면 싱글톤 클래스의 경우 프로세스 당 클래스의 인스턴스는 하나만 있을 수 있습니다.
싱글 톤 객체는 해당 클래스의 리소스에 대한 전역 액세스 지점을 제공합니다.
(위 말이 정확히 이해는 안되지만, 느낌상 전역적으로 접근이 가능하다는 걸 의미하는 것 같네요.)
싱글톤 객체는, 하나만 생성될 필요가 있는 서비스나 리소스에 사용되곤 합니다.
위 설명과 함께있는 그림인데 뻐쁠색상의 화살표 보이시나요.
이 두 뻐쁠부분이 하나는 A이고 하나는 B 입니다.
일반적인 Class는 위에서 요청하고 응답받은 것의 결과가 다르죠.(위에것은 A이고 아래는 B)
하지만 싱글톤의 경우 둘다 A 입니다.
Q. 그림이랑 설명이 아주 흐릿하게는 알겠는데, 언제쓰는지 사례를 통해서 알면 좋을 것 같아요.
A. 사례를 통해 아는 것이 좋죠. 그래야 기억도 잘나고, 실제로 사용하고 싶을 때 사용할 수 있겠죠?
상황을 가정해볼께요. 보통 앱을 만들면 로그인 기능을 구현하잖아요. 로그인을 하면 API에 POST를 합니다. 그러면 Response로 주로 "jwtToken"(이하 토큰) 이라는 값을 줍니다.
이 토큰을 가지고 앱에서 어떤 행동을 할 때, 계속 필요하죠.
예를들자면,
영상앱이라면 영상을 틀 때, 토큰값과 함께 API에 요청을 해야합니다.
게시판앱이라면, 게시판의 글을 작성하거나 댓글을 달 때 필요할겁니다.
이렇게 "전역적으로" 필요합니다. 상당히 서비스의 General 하게 사용되죠.(공식문서의 표현)
만약 이 토큰이 클래스의 UI 상 Depth가 깊은 곳에 있다면, 매번 클래스에 데이터를 전달하며 컨트롤러 간 소통을해야겠죠? init 메소드에 전달하든지, 서브스크립트로 접근하든지 델리게이트로 전달하든지, 등등요.
뭐든지 어떻게해서든지 해결은 가능합니다. 다만 효율적이지 않을 뿐입니다. 그래서 싱글톤 패턴을 사용하면 용이합니다.
토큰자체를 앱의 모든 곳에 접근 가능한 depth에 위치시키면 되는 것이죠. 그곳이 전역변수의 위치가 되는 겁니다.(전역의 뜻 자체로 전체의 구역이니까요. 모든 곳에 접근이 가능합니다.)
Q. 음.. 무언가 전역적으로 사용되는 정보나 기능들을 싱글톤으로 구현하면 좋다는 말씀이시군요. 그러면 구체적으로 어떻게 작성하는 건가요?
A. 네 다음 코드를 먼저 볼께요.
class UserInfo {
static let shared = Singleton()
var jwtToken: String?
// init 메소드를 호출해 인스턴스가 중복 생성되는 것을 막기 위해
// private 접근제어자를 사용합니다.
private init() {}
}
이렇게 정의하는게 "국룰"이라고 인지하시면 됩니다. (물론 만드시다보면, 커스터마이징 하시게되겠지만요.)
이렇게 정의했다면, 이제 사용해야겠죠?
let token = UserInfo.shared.jwtToken
서브스크립트로 접근하여 각 값을 가져오시면됩니다!
장단점을 알아야 언제 사용할 지, 언제 사용하지 말아야할 지 기준이 생깁니다. (전 그렇더라구요 ㅎㅎ)
만약 이해도가 높으신 분들이면 이 블로그의 글을 추천드립니다!
https://develogs.tistory.com/8
상당히 구조적인 관점과 많은 고려사항들을 고려하신 좋은 글이라 추천드려요!
1. 인스턴스를 2 번 생성하지 않음 -> 메모리 절약
2. 싱글톤으로 데이터 전달 및 공유가 쉬움
1. 객체지향설계원칙인 "개방=패쇄" 원칙을 위배할 가능성이 있음. (아래 추가설명)
(인스턴스 간의 결합도가 높아짐으로 인한 발생)
2. 수정과 테스트에 어려움을 초래함.
※ Open Close Principle : 개방폐쇄의 원칙
OCP란 소프트 웨어의 구성요소(ex. 컴포넌트, 클래스, 모듈, 함수)는 "확장에 대해서는 개방"되어야합니다. 반면 "변경에 대해서는 폐쇄" 되어야 합니다.
확장에 대해서 개방? 아 무언가 추가하는건 편해야한다라는 뜻이군요.
다만 폐쇄되어야 한다? 아. 추가하더라도 다른 부분이 변경되어서는 안된다는 뜻 같습니다.
이 외에도 더 장단점이 있겠으나, 좀 더 공부하고 추가하겠습니다.
정리하자면,
전역범위로 간단한 데이터 공유가 필요한 경우 사용합니다. 복잡해질 경우, 다른 방법을 고려하는 것을 추천드립니다. 이유는 의존성과 인스턴스간 결합도가 높아져 생길 사이드이펙트가 많기 떄문입니다.
https://ttuk-ttak.tistory.com/75
오 이거 이해 잘 안 됐었는데… 친절한 설명 감사합니다^__^