2018년 6월 28일 목요일

Unity Assert on Device


using System.Collections.Generic;

private readonly Dictionary<TYPE, IValue> _values = new Dictionary<TYPE, IValue>();

private void SetTable(TYPE type, IValue origin)
{
    Assert.IsFalse(_values.ContainsKey(type), type.ToString());
    _values.Add(type, origin);
}

public ITable GetTable(TYPE type)
{
    IValue value = null;
    Assert.IsTrue(_values.TryGetValue(type, out value));
    return value;
}



유니티에서 위의 코드를 사용하고 있었는데 지속적으로 핸드폰에서만 문제가 발생했다.

에디터에서는 재현이 되지 않아 로그를 추가하여 APK를 빌드하고 기기에 설치하여 Logcat 으로 로그를 확인해 보았다.

_values 에는 분명 값이 있고 _values.TryGetValue 를 사용하면 정상적인 값을 얻을 수 있었지만,  GetTable 함수를 사용하면 null 만 반환되는 문제였다.

몇 줄 되지 않는 코드라 대체 어떤것이 문제인지 도통 감을 잡을수가 없었다.

마지막이라는 심정으로 GetTable 함수의 Assert 를 제거하고 다시 APK를 빌드하여 핸드폰에서 실행하자 거짓말처럼 GetTable 함수가 정상적인 값을 반환했다.

대체 이해가 불가하여 옆자리 동료에게 물어보니 이유를 들을 수 있었다.

Assert 함수들의 소스 코드를 보면

[Conditional("UNITY_ASSERTIONS")]
public static void IsTrue(bool condition)
{
    Assert.IsTrue(condition, (string) null);
}

[Conditional("UNITY_ASSERTIONS")] 가 붙어있음을 확인 할 수 있다.

에디터에서 Assert 함수들이 잘 동작하는 이유는 유니티가 C# 프로젝트 파일을 만들때

속성에 위 스크린샷 처럼 UNITY_ASSERTIONS 속성을 강제로 넣어주기 때문이다.

APK에서는 UNITY_ASSERTIONS 속성이 정의되어 있지 않고, Assert 함수들은 동작하지 않게 된다.

게다가 GetTable 함수의 Assert 코드 위에 IValue value = null; 로 초기화까지 해 버렸다.(C++ 쓰던 습관으로)
아마 IValue value; 로 했었으면 APK 빌드 도중 컴파일 에러가 나서 더 빨리 문제를 찾을수 있었을 지도.

APK에서도 Assert 함수들을 사용하고 싶으면 UNITY_ASSERTIONS 디파인을
Player Settings -> Other Settings -> Scripting Define Symbols 에 추가하면 된다.

댓글 2개:

  1. 궁금한게 있는데요,
    IsTrue함수가 선언되어 있는 라인 전체가 사라지는건가요? 아니면 함수 내부가 동작하지 않는걸로 되는건가요?

    _values.TryGetValue 함수 자체는 IsTrue가 동작하지 않더라도 호출될거 같아서요.

    답글삭제
    답글
    1. Conditional Attribute에 대해 좀더 구글링 해보시면 답나옵니다
      결론적으로 정답은
      Assert.IsTrue(_values.TryGetValue(type, out value)); 이 코드는 통채로 건너뜁니다.

      물론 개발하시다가
      의문점이 든다면 가장쉬운방법은 중단점찍고 확인해보는거죠 ㅋㅋ

      삭제