Curious to see how efficient you guys think this code is, and if there are better ways to code it. I use this in my game to grab GUI instances with clean code.
function gui:Get(...)
local guis = {...};
local object = gui.Container;
for _, guiObject in pairs(guis) do
if (object:FindFirstChild(guiObject)) then
object = object:FindFirstChild(guiObject);
elseif (object:FindFirstChild(guiObject, true)) then
object = object:FindFirstChild(guiObject, true);
else
while (not object:FindFirstChild(guiObject)) do wait() end
object = object:FindFindFirstChild(guiObject);
end
end
return object;
end
How it Works
This function was specifically created for grabbing any GUI instance within a parent instance. gui.Container refers to a frame that contains all GUI in my game (StarterGui.Main.Container) The function declares the variable object as the ârootâ instance to search through, then searches through all descendants of object until it finds it. Please note that this function expects the object to be there, or else there will be an infinite yield. The function also only returns the first occurrence of the instance that it is searching for.
Syntax
Since gui.Container (StarterGui.Main.Container) is the root object, any argument of gui:Get() is expected to be a descendant of gui.Container
Example:
(For grabbing StarterGui.Main.Container.Backpack.Items.Container.Banana): gui:Get("Backpack", "Banana");
Probably should have tested this first, since âFindFindFirstChildâ would error
Anyways, hard to tell why youâd want to use this instead of just the recursive FindFirstChild. The main difference, it seems, is that your function can tell you which ancestor to search in, i.e. Container.Backpack.Items.Banana and not Container.Backpack2.Items.Banana
But in that case I donât see why you wouldnât just use something likeâŚ
local backpack = container:FindFirstChild("Backpack", true)
local banana = backpack:FindFirstChild("Banana", true)
--Or with your function, something like...
function gui:Get(...)
local guis = {...};
local object = gui.Container;
for _, guiObject in pairs(guis) do
object = object:FindFirstChild(guiObject, true)
end
return object;
end
This way you wouldnât get infinite yields for something that doesnât exist (and for that matter, your function would yield infinitely even if âBananaâ was added to Items.Container later on, since it doesnât search recursively for it).
Donât use pairs() for this, it may work for now but itâs not guaranteed to iterate over the key-value pairs in any specific order. Using ipairs() would be an easy fix, but using a for loop would be fastest.
Also at a glance there are some redundant :FindFirstChild calls, but I doubt youâre running this enough to have any significant performance impact.
Iâm genuinely curious as to what prevents me from just using ::GetDescendants() and filtering the results instead. Maybe Iâm misreading what this is intended for?
Instead of using a while-loop, you can use the DescendantAdded event to detect when a new descendant was added. Hereâs my refactor of your code:
function gui:Get(...)
local guiNames = {...}
local object = gui.Container
for _, guiObjectName in ipairs(guiNames) do
local newObject = object:FindFirstChild(guiObjectName, true)
while newObject == nil do
object.DescendantAdded:Wait()
newObject = object:FindFirstChild(guiObjectName, true)
end
object = newObject
end
return object
end