[SerializeField] int age;
private void Start()
{
Debug.Log(age);
}
직렬화된 int 변수 age를 가지고 있는 스크립트를 하나 만들고,
유니티 Hierachy에서 세개의 컴포넌트를 만들어주고 값을 달리 준 다음 실행하면
각기 다른 값이 나온다.
메모리를 나타낸 그림을 보면
Test 클래스를 프로젝트에 만들었고 이 자체로는 메모리 할당이 일어나지 않지만
게임오브젝트에 스크립트를 드래그 해서 넣을 때 서로 다른 메모리 공간에 할당이 되어 객체가 생성된다.
One의 age값을 바꿔도 자신의 age 값만 바뀌지, Two와 Three의 값이 같이 바뀌진 않는 것이다. (서로 영향 X)
그렇다면 모든 객체의 나이의 값이 모두 똑같아야 한다면 어떻게 해야 할까?
static
static 키워드를 사용하면 된다.
Static이란,
변수 / 함수 / 클래스에 정적(static) 속성을 부여하여 클래스에서 객체를 생성하지 않고
변수나 함수를 호출할 수 있는 기능
- static 변수
static int age = 10;
[ContextMenu("나이 출력")]
private void PrintAge()
{
Debug.Log(age);
}
[ContextMenu("나이 증가")]
private void PlusAge()
{
age++;
}
방금처럼 세개의 컴포넌트를 만들고 각각 위의 스크립트를 넣어준 후
PlusAge를 실행하면 모든 객체의 age 값이 1 증가한다.
메모리 그림으로 살펴보면,
One, Two, Three와 같은 객체들은 static int age의 메모리를 절대 갖고 있지 않고,
static int age는 메모리에 딱 하나만 올라가있다.
모든 객체들은 다 static int age를 참조하고 있기 때문에 어느 객체에서 함수를 실행하여 age의 값을 증가시키면,
모든 객체의 값이 똑같이 증가한다.
사용 예시 - 싱글톤
public class StaticTest : MonoBehaviour
{
public static StaticTest Instance { get; private set; } //단 하나의 클래스에 있는 단 하나의 인스턴스(객체)
private void Awake()
{
if (Instance == null) //만약 이 클래스가 중복되지 않는다면
{
Instance = this; //인스턴스는 자기 자신이라고 지정 (GetComponent<StaticTest>() 와 같다)
DontDestroyOnLoad(gameObject); //씬이 넘어가도 파괴하지 않게 하기
}
else Destroy(gameObject); //만약 중복되면 파괴하기
}
}
public class OtherClass
{
void Start()
{
StaticTest.Instance. //...동작 수행
}
}
https://wonseok1112.tistory.com/5
싱글톤 참고자료
- static 함수
StaticFunc라는 static 함수를 만들어줬다.
그런데, 함수 안에서 static 변수는 참조가 가능한데 일반 변수는 참조가 불가능하다.
StaticFunc 함수는 static int age와 같이 Test 클래스에 소속되어 있기 때문에 static 함수는 static 변수만 참조가 가능하다.
인스턴스(객체)가 생성될 때 할당되는 일반 변수는 클래스에서 찾을 수 없고
인스턴스를 생성했을 때 만들게 된다.
다른 스크립트에서 스태틱 함수를 호출하는 방법
public StaticTest staticTest; //1
// ...
private StaticTest staticTest; //2
staticTest = GetComponent<StaticTest>();
//...
StaticTest staticTest = new StaticTest();
다른 스크립트에서 일반함수를 호출할 때는
원래 이런 식으로 객체를 생성한 후, staticTest.함수(); 로 함수를 호출해야 했지만
private void Start()
{
StaticTest.StaticFunc();
}
스태틱 함수를 호출할 때는 객체를 생성하여 참조하고 함수를 호출할 필요 없이,
위처럼 클래스 자체를 참조하여 호출한다.
위에서 말했듯이 일반 함수는 객체를 생성했을 때 만들어지기 때문에 객체를 참조하여 함수를 호출해야했지만,
스태틱 함수는 클래스 자체에만 존재하기 때문에 클래스 자체를 참조하여 호출하는 것이다.
- static 클래스
public static class StaticClass
{
static int age = 18;
public static void StaticFunc()
{
Debug.Log("static class");
}
}
스태틱 클래스는 MonoBehaviour를 상속받을 수 없고, 클래스 내에 스태틱 변수와 스태틱 함수만이 존재할 수 있다.
스태틱 클래스 안에 있는 함수를 호출하는 것은 위의 방법과 똑같다.
따라서 사실 static 클래스는 확장 메서드를 사용하는 경우가 아닌 이상 잘 쓰이지는 않는다.
일반 클래스에다가 static 함수와 static 변수를 사용하는 것이 MonoBehaviour도 상속받을 수 있고,
일반 변수도 생성할 수 있는 등 여러모로 더 편리하기 때문이다.
- 확장 메서드
static 클래스를 이용하여 만든
들어온 string 매개변수를 TryParse를 사용하여 float로 변환이 가능한지 확인하고
bool값을 변환하는 확장 메서드이다.
이런 식으로 string 변수 s를 만들고, s에 .을 찍어보면 마치 원래 있던 내장함수처럼 아까 만들었던 함수가 나온다.
사용 예시
매개변수로 넣은 float값만큼 transform의 x값만 움직이는 확장 메서드
주의점 & 느낀점
static 키워드가 편리하다고 마구잡이로 사용하면 안된다.
static은 데이터(Data) 영역에 할당되므로, static을 선언하는 즉시(컴파일 타임) 데이터에 저장이 된다.
(런타임 이전에 이미 생성) 그리고 어플리케이션을 종료하기 전까지 쭉 가지고 있다.
사용하지 않을 때나 필요하지 않을 때에도 가비지컬렉터(GC)가 실행되지 않기 때문에 메모리 낭비가 심하다.
따라서 거의 변할 일이 없는 변수나 함수에만 사용하는 것이 효율적이다.
static 키워드는 솔직히 싱글톤 만들때 말고는 많이 사용하진 않았는데,
static 키워드를 이용한 확장 메서드 기능은 정말 유용해보였다. 앞으로 프로젝트에서
필요할 때 static 키워드를 애용해야겠다는 생각이 들었다.
'C# 기초' 카테고리의 다른 글
[C#] 상속 - 인터페이스(interface) (0) | 2023.10.25 |
---|---|
[C#] 상속 - abstract(추상), virtual(가상) (0) | 2023.10.25 |
[C#] Collections (0) | 2023.10.24 |
[C#] ref, in, out 참조에 의한 호출 (0) | 2023.10.23 |
[C#] 값 형식과 참조 형식 (1) | 2023.10.23 |