- Home /
Editor DestroyImmediate Remove component via script
My issue: I would like to add a component dynamically at Design/Editor Time if a checkbox is on and remove it if checkbox is off.
My code: Component1 uses [CustomEditor(typeof(Component1))] and Component2 uses [CustomEditor(typeof(Component2))]
ObjSceneComp is target of Component1 Inspector GUI.
if(CheckboxComponent1) { //if no Component2 added if(Component2Exists== false) { ObjSceneComp.gameObject.AddComponent<Component2>();
}
}
else {
if(Component2Exists== true) {
DestroyImmediate( ObjSceneComp.gameObject.GetComponent<Component2>());
}
}
}
It all works fine, but I always get this error: MissingReferenceException: The object of type 'EKISharedDataComponent' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object.
If I take instead of Component2 an normal script without a CustomEditor behind Unity is going to crash.
You just posted some snippets of your code, but i can't deter$$anonymous$$e what it is supposed to do. What is ChechboxComponent1 and where is it set? What is Component2Exists and where is it set? Is "test" relevant for your problem? $$anonymous$$aybe edit your question and add relevant code and remove irrelevant parts.
ChechboxComponent1 is set within the CustomEditor-GUI for component1. Sorry my mistake: test is Component2Exists please substitute test through Component2Exists. within the start test is always false.
Answer by margutteter · Apr 24, 2015 at 03:51 AM
I found another solution for this... If a custom inspector removes a component on the same game object, during the same iteration of drawing the inspector, Unity will encounter the removed component and error trying to draw it.
Using EditorGUIUtility.ExitGUI() will stop the execution of the current draw iteration, starting over from the top, at which point the removed component will not be attempted to be drawn.
It's also good to note that calling EditorGUIUtility.ExitGUI() in the scope of OnInspectorGUI() will also interrupt the execution of the Inspector of the current component (having the same effect as "return;"), not just the next components. So you should only call this after all the code you need in the current inspector has been executed.
That's pretty irrelevant for several reasons.
First of all the current execution of the inspector is an input event and not a repaint event so there will be no visual difference. It has to be an input event (like "mouseup" ) since you most likely removed the component in reaction to a button click or key press.
Next thing is since some component has handled that input event (for example a Button has called "Use()" on that event), the event type is set to "Ignore" for everything that follows, no matter if it's in your inspector or in any other. So the event has no use for anything else. It just causes problems hence the ExitGUI
Finally when you call ExitGUI you actually raise an exception that is silently caught by Unity. Unity will immediately repaint the whole inspector anyways. So it doesn't matter if you call ExitGUI adter some other things or not ^^.
ExitGUI is also used by some internal controls. You need it when you somehow start a new GUI call due to some actions. A common case are native popup windows or opening EditorWindows from inside the inspector. One example i can think of is the ColorField. When you click on it, it opens the color picker window. After opening the window it immediately called ExitGUI to prevent the corruption of the layout stack which has been altered by the just opened window.
This is the snipped which is executed when you click with the left mouse button onto the ColorField:
{
GUIUtility.keyboardControl = id;
EditorGUI.show$$anonymous$$ixedValue = false;
ColorPicker.Show(GUIView.current, value, showAlpha, hdr, hdrConfig);
GUIUtility.ExitGUI();
}
I don't see why this is irrelevant in any way. The fact that ExitGUI() is raising a silent exception is especially the reason why it's important to make sure that all the code you need is called before calling ExitGUI(). Your example does not di$$anonymous$$ish my point in any way, all the relevant execution is done before ExitGUI().
$$anonymous$$aybe you'll understand why this is valuable information with an example. Let's say I want to replace one component with another, doing this won't work:
public override void OnInspectorGUI()
{
if(GUILayout.Button("Change components")){
ClearFooComponents();
AddBarComponents();
}
}
private void ClearFooComponents()
{
Component selectedComponent = target as Component;
Component[] fooComponents = selectedComponent.GetComponents<Foo>();
foreach (Component currentComponent in fooComponents)
{
DestroyImmediate(currentComponent);
}
EditorGUIUtility.ExitGUI();
}
As ExitGUI() is called in the ClearFooComponents() function, AddBarComponents() will never be executed. $$anonymous$$nowing that calling ExitGUI() interupts the flow of execution is relevant information. For the code to work you would have to call ExitGUI() after AddBarComponents().
Answer by psyfreak · Mar 19, 2011 at 01:21 PM
I solved it myself:
You have to hide it it via a flag from your script. That flag you have to use for (un-)hiding in OnInspector function. If the component is hidden, then you can do the the DestroyImmediate as far as you have no scripts or other comps, which access your current component.
Not sure if something has changed in Unity 5, but just setting the hide flags doesn't seem to work.
Here's the super-hacky way I solved it:
Within your custom editor script, save the component you want to destroy to a private static variable
Set the hide flags (I just used (HideFlags)int.$$anonymous$$axValue)
Then, at the top of your OnInspectorGUI function, add a check to delete the component if it's not null. That will force a deletion the following frame, and you won't see the exception.
Answer by steven3Dim · Jun 22, 2017 at 08:51 AM
The problem is that the component is still visible in the inspector. Instead of calling
DestroyImmediate(CharacterDecal);
Use:
CharacterDecal.hideFlags |= HideFlags.HideInInspector;
DestroyImmediate(CharacterDecal);
This worked for me on Unity 5.5.3f1
Edit: Oh this doesn't work: seems I tested it in play-mode.
If you can live with not having the component in the editor, you could set
CharacterDecal.hideFlags |= HideFlags.HideInInspector;
immediately when you created the component. The problem arises, because in the same frame the inspector is draw, it still holds a reference. So your component should be hidden already in the frame before you destroy it, or there should be a way to correctly notify the inspector, which I found not. Some users say to use UnityEngine.GUIUtility.ExitGUI () which throws an exception, but it is an internal function only and only has effect when in the GUI drawing routine I suspect.
Answer by That1phillps · Oct 21, 2019 at 09:32 PM
But before all of these things, first try restarting your computer. I did that, and it worked...
Your answer
Follow this Question
Related Questions
(Editor) How to delete duplicate components from GameObject that persists when the scene reloads 0 Answers
Component Find and Replace: execute's fine, fails to do anything?! 1 Answer
Get GameObject from List based on attached script or assigned name 3 Answers
2D Animation does not start 1 Answer
GameObject permanent destruction from "Resources" in EditorWindow 0 Answers