Unity3D/유니티 공부

[Unity / C#] 인보크(Invoke)

상연 2022. 4. 29. 02:52

목차

    인보크(Invoke)


    단순히 게임이 아니더라도 개발을 하다 보면 특정 함수를 일정 시간 이후에 실행시켜야 할 필요가 생긴다.

    이럴 때 사용하는 기능이 인보크(Invoke)이다.

    인보크는 아주 간단하게 함수의 이름과, 시간을 인자로 받아 그 함수를 받은 인자만큼의 시간 이후에 실행한다.

    float t;
        private void Start()
        {
            t = 0;
            Invoke("tryInvoke", 5.0f);
        }
    
        private void Update()
        {
            t += Time.deltaTime;
            Debug.Log($"Now Time : {t}");
        }
    
        void tryInvoke()
        {
            Debug.Log("Invoke 실행!");
        }

    위의 코드를 봐 보자.

    tryInvoke() 함수를 Invoke를 사용하여 5초 후에 실행시킨다는 코드가 Start()에 들어있으며

    Update()에서는 프레임 단위로 시간을 측정하고 있다.

    그리고 실행 결과는 위와 같다.

    5초 후에 Invoke에 들어있는 함수가 실행됐음을 알 수 있다.

     

    형식

    Invoke( "함수명"(string) , 지연시간(float));

    형식은 매우 간단하다.

    실행시키고자 하는 함수 이름과 시간만 있으면 된다.

    단, 함수 매개변수를 String 타입으로 넣어주기 때문에 에디터가 매개변수로 들어간 이름의 함수가 실제로 있는지 없는지 알 수가 없다. 그렇기 때문에 함수 이름을 잘못 입력하면 Invoke는 실행되지 않는데 에디터 상에서는 문제를 찾기 힘들기 때문에 매개변수를 입력할 때 두 번 세 번 잘 보고 넣어야 한다.

     

    유니티 인보크에 매개변수를 전달?

    결론만 말하면 할 수 없다.

    인보크는 단순히 함수의 이름만 전달할 수 있으며 매개변수 전달은 꿈도 꾸지 말자.

    함수의 지연 실행 + 매개변수 전달이 필요하다면 Coroutine을 사용해야한다.

    Invoke는 단순한 지연 실행에 있어서는 Coroutine보다 간편하지만, 성능면에서는 떨어진다.

     

    InvokeRepeating 인보크 반복 실행


    위에서 본 Invoke함수는 인자로 들어온 함수를 단 한 번 실행한다.

    하지만, InvokeRepeating을 사용하면 프로그래머가 지정한 주기로 반복해서 실행할 수 있다.

    마찬가지로 Coroutine으로도 구현이 가능하지만 InvokeRepeating 자체가 조금 더 간편한 편이다.

    private void Start()
        {
            InvokeRepeating("tryInvoke", 1.0f, 1.0f);
        }
        void tryInvoke()
        {
            Debug.Log($"Invoke 실행! {Time.time}");
        }

    이러한 코드로 테스트를 해 보겠다.

    tryInvoke 함수를 1초 후 실행한 후, 1초 간격으로 반복할 것이다.

    tryInvoke는 실행될 때마다 Debug.Log를 통해 프로그램이 실행된 후 지난 시간을 출력한다.

    형식

    InvokeRepeating( 함수 이름(String), 지연시간(float), 반복 간격(float));

    따라서 위의 프로그램은 실행 후 1초 뒤에 tryInvoke 함수가 실행되고,

    그 이후에 1초 간격으로 tryInvoke가 계속 반복된다.

     

     

    CancelInvoke 인보크 취소


    그런데, 반복하는 것은 좋은데 보통 함수의 반복을 프로그램의 시작부터 끝까지 하는 경우는 거의 없을 것이다.

    반복을 시켰으면 종료도 시킬 수 있으면 좋겠는데...

    해서 CancelInvoke 함수가 있다. 이를 통해 인자로 받은 Invoke 함수의 실행을 멈출 수 있다.

    CancelInvoke("함수명"(String));
        private void Start()
        {
            InvokeRepeating("tryInvoke", 1.0f, 1.0f);
            Invoke("stopInvoke", 5);
        }
        void tryInvoke()
        {
            Debug.Log($"Invoke 실행! {Time.time}");
        }
    
        void stopInvoke()
        {
            CancelInvoke("tryInvoke");
        }

    이와 같은 코드로 테스트해 보겠다.

    조금 응용을 해서 멈추는 함수를 Invoke를 사용하여 5초 후에 실행하게 했다.

    물론 Invoke 함수에는 매개변수를 전달할 수 없으므로 매개변수가 없는 빈 함수를 만들고 그 안에서 CancelInvoke가

    실행되도록 한 다음 그 함수를 Invoke가 5초 후 실행하게 하였다.

    5번째까지 실행될 것이라는 예상과는 다르게 종료 시간을 반복 간격과 딱 맞추었더니 마지막은 실행이 되지 않았다.

    Coroutine이 아닌 Invoke로 특정 범위 안에 반복을 가할 생각이라면 이러한 딜레이를 고려할 필요가 있다.

     

    Invoke 성능에 관한 이야기


    C#에는 아주 강력한 기능이 있다. Reflection이라는 것인데

    이는 프로그램 실행 도중에 객체의 정보를 조사하거나, 다른 모듈에 선언된 인스턴스를 생성한다던지, 기존 개체에서 형식을 가져오고 해당하는 메서드를 호출, 접근할 수 있는 아주 강력한 기능을 갖고 있다.

    하지만 강력한 만큼 단점이 있다. 느린 편이다.

    이 이야기를 왜 했느냐 하면

    Invoke( "함수명"(string) , 지연시간(float));

    Invoke는 Coroutine이 메서드 자체를 인자로 받아가는 것과는 달리, 메서드의 이름을 받아간다.

    이 부분이 바로 Reflection을 통해 값을 가져가는 것인데 이 과정이 Coroutine보다 느리다는 것이다.

    따라서 Unity 공식문서에서도 성능을 원한다면 Invoke보다 Coroutine을 권장한다고 쓰여있다.

     

    오브젝트가 비활성화되어도 인보크는 살아있다


    따라서 실행된 인보크(Invoke)를 중지하기 위해서는 CancelInvoke를 사용하거나, 오브젝트를 파괴시켜야 한다.