This post is just informative, and I hope it will help someone to avoid 1 day of time wasting. I even couldn’t imaging that text engine could have buggy behaviour in the main method.
So, what’s the case exactly?
If you use TextMeshPro.SetText() method applying any value to the text component, it will change the view (visuals will be updated) but checking that text by TextMeshPro.text property you ALWAYS will get empty string (or string, which been applied before in inspector or using same TextMeshPro.text property) in any build. I been working on Standalone app, and this issue happened both Mac and Win.
Here is a part of code from TMP_Text.cs
public void SetText(string text, bool syncTextInputBox)
{
//if (text == old_text) return;
//old_text = text;
m_inputSource = TextInputSources.SetCharArray;
StringToCharArray(text, ref m_TextParsingBuffer);
#if UNITY_EDITOR
// Set the text in the Text Input Box in the Unity Editor only.
// TODO: Could revise to convert to string literal
if (syncTextInputBox)
m_text = text;
#endif
m_isInputParsingRequired = true;
m_havePropertiesChanged = true;
m_isCalculateSizeRequired = true;
SetVerticesDirty();
SetLayoutDirty();
}
As you see it will update m_text only in Editor.
This behaviour is used in all currently official TMP versions. For Unity 2018 it’s 1.4.1, for Unity 2019 it’s 2.0.1
In new preview versions they fixed it changing the method to simple
What makes it the same as TextMeshPro.text direct property change. Do I miss something or both version are pretty… weird…
I hope this help. Would be great to get some response from TextMeshPro dev team with an explanation, how this part of code can be affected to such basic methods.
The SetText() method was initially added to allow users to combine variables along with the text without allocations.
For example : m_TextComponent.SetText(“The value is: {0:1}.”, 10.45f); which would result in “The value is: 10.5.”.
Since this SetText() function never internally set the .text property which to avoid allocations which left the Text Input Box in the Inspector empty, a change was made so that in the Editor Only, the .text property was set to match the SetText() with formatting content.
At some other point in time, users requested the ability to user StringBuilder and as such
public void SetText(StringBuilder text) was added as well as other variants of SetText().
All along is was possible to use SetText() without formatting but that provided no benefits and also resulted in allocations in the Editor to set the .text property for the Inspector. So in order to avoid that, the plain SetText() with no formatting was simply replaced to set the .text property.
There have been several threads about this over the years including this one from last week. This new thread includes a good suggestion from @Gladyon which I intend to explore when I have a chance.
I also ran into this and while I like the ability to avoid garbage allocation as you mentioned, right now the implications aren’t obvious. As a result, it sounds like something people can run into often and specifically at inopportune times because most issues only happen in a build!
My specific scenario is that I had my localization system use SetText(), and another script which would copy the text to another TextMeshProUGUI component. (which we do to work around this issue)
A few suggestions I have for this:
Add documentation to the SetText() function, explicitly noting there is a difference in editor/build & explaining the use case. (something like along the lines of: “In order to avoid GC Alloc, the .text value is not updated. SetText() should only be used when you intend on only writing to the text, not reading”)
Make the editor & build behave the same, though I’m not sure how hard this is to do. (I can imagine it being very difficult due to .text dependencies in-editor or smth)
Possibly rename SetText(0 to SetTextNonAlloc() to be more explicit in its purpose, though I understand that may not be a good idea due to legacy / package being distributed already.
I’m so glad I managed to find this, I was struggling for a solid 6-8 hours as to why my text was being processed differently in my build vs. the editor. Replacing ‘TextMeshPro.SetText()’ with ‘TextMeshPro.text =’ solved everything.
Thank you guys for resolving this. For me it was 3 hours of searching in the dark…
Replacing ‘TextMeshPro.SetText()’ with ‘TextMeshPro.text =’ solved everything for me aswell.