I’m using OnValidate (first time I’ve used that function, incidentally), and I’ve run into a significant and nonsensical problem with it: there’s no way to destroy objects. Destroying (and recreating) child obejcts is like 99% of what I would ever want to use OnValidate for.
Let me elaborate. So I tried to use DestroyImmediate, because this is an editor function and that’s what you do in the editor. It gives me this:
Destroying GameObjects immediately is not permitted during physics trigger/contact, animation event callbacks or OnValidate. You must use Destroy instead.
UnityEngine.Object:smile:estroyImmediate(Object)
BranchGenerator:OnValidate() (at Assets/BranchGenerator.cs:19)
UnityEditor.DockArea:OnGUI()
Weird, I think. Why would it want me to use Destroy in OnValidate, which can only ever be run outside play mode? I give it a shot, and as expected:
Destroy may not be called from edit mode! Use DestroyImmediate instead.
Also think twice if you really want to destroy something in edit mode. Since this will destroy objects permanently.
UnityEngine.Object:smile:estroy(Object)
BranchGenerator:OnValidate() (at Assets/BranchGenerator.cs:19)
So, let me reiterate: Why would it want me to use Destroy in OnValidate, which can only ever be run outside play mode? Also, how the hell am I supposed to destroy objects in OnValidate?
(And on a related note: I’ve never understood the reason for having Destroy and DestroyImmediate be two different functions. Just have Destroy see if we’re in Editor mode, and if appropriate call DestroyImmediate.)
There is a more fundamental difference to those functions. DestroyImmediate() really does immediately destroy the data right away whereas Destroy() waits until script execution has finished and only then destroys the object(s). This is much safer as it won’t destroy objects that are actively being worked on.
Also, it’s actually the reverse concerning play mode, i.e. you can only call Destroy() while in play mode.
However, the situation you are describing with one referring you to the other and producing a stalemate where you can call neither is a rather unfortunate one. That warrants deeper investigation…
I understand they behave differently, but why two different functions? Why not simply note the different behavior in the docs - “When called from outside Play Mode, Destroy will destroy the object immediately; when called from inside play mode, it will wait until the end of script execution.” There is never a situation where you can actually choose which one to use, right? It’s always one or the other.
In the current state of things, I have to do this ridiculousness anytime I have a generator function that may be called from either play mode or the editor:
if (Application.isPlaying) Destroy(thing);
else DestroyImmediate(thing);
I know this is 6 months old so, in case this is still of any interest to you…
In edit mode, DestroyImmediate remains unsafe. I’m encountering cases where the editor crashes on me, or hangs, because it’s not happy about when I invoke this function. Yes, these are often the cases when it turns out to be most useful.
You can postpone destruction in a variety of ways as PrefabEvolution already suggested.
Even so, DestroyImmediate has the tricky advantage that it does what it says, and does it right away. Having unwanted objects lingering inside the runtime often ends up with code doing things with an object that shouldn’t be there.
Although its use is strongly discouraged, calling DestroyImmediate() at runtime isn’t technically forbidden (unless that changed recently?); you do it at your own risk - a risk no greater than deleting Objects in C++.
Since I’m strongly against GC style object management (because I don’t want objects to exceed their welcome in my runtime) I would rather these two functions continue to exist side by side.
Destroy() is still very useful and reliable enough in 99% of cases. Would be nice to be able to use it in edit mode; I understand edit mode would never honour the destroy request in the current implementation. Does it mean it cannot be made to work?
The issue is still there in Unity 4.6.3, but now attempting to use DestroyImmediate() results in slightly different message:
Destroying components immediately is not permitted during physics trigger/contact, animation event callbacks or OnValidate. You must use Destroy instead.
Still displaying this confusing (and ultimately invalid) message in 5.3.4p3
It would be even better to include a link to this thread in the error message…
Friendly advice here!
Instead of DestroyInmediate, use the Undo version for it: otherwise you can’t undo the destruction!
This code will take care of the destruction in editor + make it undoable
Oh and by the way, you can use it for multiple objects (I use it to destroy several components that require each other) and it will still record a single UNDO step, which is nice
I know this is an old thread but another approach would be to implement your own Destroy() Method in the MonoBehaviour you want to destroy and call it with Invoke()