Last active
August 30, 2020 18:18
-
-
Save Corecii/4099b26127f0bbb3431dd9853ec100ff to your computer and use it in GitHub Desktop.
Roblox Instance Destroyed and Garbage Collected Example Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Notable behavior: | |
* ObjectValues will get their Value set to nil if: | |
* The ObjectValue is in nil | |
* its Value is in nil | |
* its Value gets garbage collected because it has no string reference | |
* When an object gets garbage collected, all of its connections get disconnected. | |
* Connections that don't hold a reference to the object won't prevent garbage collection!! | |
* When an object gets destroyed, connections are disconnected by the next Heartbeat | |
We can make use of these behaviors to detect when an object is both destroyed and garbage collected | |
]] | |
local OnDestroyed = {} | |
function OnDestroyed.onInstanceGarbageCollectedSimple(instance, callback) | |
local weakReference = Instance.new("ObjectValue") | |
weakReference.Value = instance | |
instance = nil | |
coroutine.wrap(function() | |
while weakReference.Value ~= nil do | |
wait(5) | |
end | |
callback() | |
end)() | |
end | |
-- The following will not detect if an object is already in nil and gets Destroyed: | |
function OnDestroyed.onInstanceDestroyedSimple(instance, callback) | |
local connection | |
connection = instance.AncestryChanged:Connect(function() | |
game:GetService("RunService").Heartbeat:Wait() | |
if not connection.Connected then | |
callback() | |
end | |
end) | |
instance = nil | |
end | |
function OnDestroyed.onInstanceDestroyedOrGarbageCollected(instance, callback) | |
local weakReference = Instance.new("ObjectValue") | |
weakReference.Value = instance | |
instance = nil | |
local changeIndex = 0 | |
local connection | |
local function onChanged() | |
changeIndex = changeIndex + 1 | |
-- Detects Destroyed and Garbage Collected: | |
game:GetService("RunService").Heartbeat:Wait() | |
if not connection.Connected then | |
callback() | |
return | |
end | |
-- Detects Garbage Collected: | |
if not weakReference.Value:IsDescendantOf(game) then | |
local thisChangeIndex = changeIndex | |
while connection.Connected do | |
wait(5) | |
if changeIndex ~= thisChangeIndex then | |
return | |
end | |
end | |
callback() | |
end | |
end | |
connection = weakReference.Value.AncestryChanged:Connect(onChanged) | |
-- If the object is already in nil, we need to start running the GC detector: | |
coroutine.wrap(onChanged)() | |
end | |
return OnDestroyed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local OnDestroyed = require(game.ReplicatedStorage.OnDestroyed) | |
local function testCase(name, setup) | |
local f = Instance.new("Folder") | |
setup(f) | |
OnDestroyed.onInstanceDestroyedOrGarbageCollected(f, function() | |
print("Test case \"" .. name .. "\" destroyed or garbage collected") | |
end) | |
f = nil | |
end | |
testCase("nil", function() end) | |
testCase("nil -> destroy", function(f) | |
delay(2, function() | |
f:Destroy() | |
end) | |
end) | |
testCase("workspace -> destroy", function(f) | |
f.Parent = workspace | |
delay(2, function() | |
f:Destroy() | |
end) | |
end) | |
testCase("workspace -> nil", function(f) | |
f.Parent = workspace | |
delay(2, function() | |
f.Parent = nil | |
end) | |
end) | |
testCase("workspace -> nil -> workspace -> nil", function(f) | |
f.Parent = workspace | |
delay(2, function() | |
f.Parent = nil | |
wait(2) | |
f.Parent = workspace | |
wait(2) | |
f.Parent = nil | |
end) | |
end) | |
testCase("workspace -> nil -> workspace -> destroyed", function(f) | |
f.Parent = workspace | |
delay(2, function() | |
f.Parent = nil | |
wait(2) | |
f.Parent = workspace | |
wait(2) | |
f:Destroy() | |
end) | |
end) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment