InstanceHandle¶
A lightweight, weak reference to an Instance that might not be available locally.
Not implemented in Nova
This datatype is not registered in Nova's Lua VM. Constructing or receiving it from an API call will not work.
Description¶
The InstanceHandle data type is a weak reference to an Instance that might not be available locally. Use it to point at an instance that hasn't arrived yet, could stream out, or exists only on another machine, and to pick that instance up once it's there.
A handle always refers to the same target. To reach that target, call InstanceHandle.Wait(), which yields until the instance is available:
local Workspace = game:GetService("Workspace")
local part = Instance.new("Part")
local target = Instance.new("Part")
target.Name = "TargetPart"
part.Parent = Workspace
target.Parent = Workspace
part:SetAttribute("Target", target)
local handle = part:GetAttribute("Target")
local instance = handle:Wait(10)
if instance then
print("Target is", instance.Name) --> Target is TargetPart
end
Prefer InstanceHandle.Wait() with a timeout so your code runs as
soon as the instance shows up. Use InstanceHandle.Get() when you
want an immediate answer and can handle nil, such as in code that runs every
frame.
Examples¶
Attributes¶
Attributes use InstanceHandle instead of an ordinary instance
reference. Since the handle itself is never nil, you can tell apart an
attribute that is missing from one where the instance is not currently
present:
local part = Instance.new("Part")
print(part:GetAttribute("Target")) --> nil
part:SetAttribute("Target", InstanceHandle.new(nil))
local handle = part:GetAttribute("Target")
print(handle:Get()) --> nil
InstanceHandle attributes also appear in
Instance.GetAttributes(), which can't hold nil values.
Instance.GetAttributeChangedSignal() fires when the attribute is set to a new target or removed. It does not fire when the target streams in or out, or when the target is destroyed. To react to availability, combine the signal with InstanceHandle.Wait():
local part = Instance.new("Part")
part:GetAttributeChangedSignal("Target"):Connect(function()
local handle = part:GetAttribute("Target")
if not handle then
return
end
local instance = handle:Wait(10)
if instance then
print("New target:", instance.Name)
end
end)
Remote events¶
Pass a handle through a RemoteEvent to give the receiver a reference to an instance it doesn't have yet. The receiver waits for the instance instead of getting nothing.
In a server script, call this function with your remote event, the receiving player, and the model to send:
local function sendHandle(remoteEvent: RemoteEvent, player: Player, spawnedModel: Model)
local handle = InstanceHandle.new(spawnedModel)
remoteEvent:FireClient(player, handle)
end
In a client script, call this function with the same remote event to start listening before the server sends the handle:
local function receiveHandles(remoteEvent: RemoteEvent)
remoteEvent.OnClientEvent:Connect(function(handle)
local model = handle:Wait(10)
if model then
print("Received", model.Name)
end
end)
end
Ownership¶
A handle acts as a weak reference. It never keeps its target alive. The lifetime of the target is controlled by the rest of your experience: its parent and any ordinary references your scripts hold that prevent it from being garbage collected.
InstanceHandle.Get() and InstanceHandle.Wait() return an ordinary instance reference, which does keep the instance alive for as long as you hold it.
A handle is otherwise lightweight and needs no cleanup.
Equality¶
Two handles are equal when they refer to the same target, even if you created them separately and even after the target is gone. All empty handles are equal to each other. Each handle is still a distinct value.
local instance1 = Instance.new("Part")
local instance2 = Instance.new("Part")
local a = InstanceHandle.new(instance1)
local b = InstanceHandle.new(instance1)
local c = InstanceHandle.new(instance2)
print(a == b) --> true
print(a == c) --> false
Equality depends on target identity, so it still works when the target isn't currently available.
Constructors¶
new Not yet Returns a new InstanceHandle referring to the given Instance.
Returns a new InstanceHandle referring to the given Instance.
The handle refers to the instance weakly and doesn't extend its lifetime.
local target = Instance.new("Part")
target.Name = "TargetPart"
local handle = InstanceHandle.new(target)
local empty = InstanceHandle.new(nil)
print(handle:Get()) --> TargetPart
print(empty:Get()) --> nil
Throws if instance is neither an Instance nor nil.
Methods¶
Get Not yet Returns the referenced Instance if it's available locally, otherwise nil.
Returns the referenced Instance if it's available locally,
otherwise nil.
This method doesn't yield.
Get() returns nil when the handle is empty, when the target hasn't
arrived on the client or server running the script, when the target is no
longer available after streaming out, when the target has been garbage
collected, and when the target isn't accessible to the calling script. Use
InstanceHandle.Wait() to yield until the target arrives instead
of checking once.
Wait Not yet Yields until the referenced Instance is available locally, then returns it.
Yields until the referenced Instance is available locally, then returns it.
Returns nil if the handle is empty, the target is inaccessible to the
calling script, or timeout elapses first. Wait() returns immediately
when the target is already available and when the handle is empty.
Pass a timeout whenever you can't guarantee that the target reaches the
caller. A target that's destroyed before it replicates leaves a handle
that never resolves, and a Wait() with no timeout never returns. A
pending wait can't be cancelled: task.cancel() stops your
coroutine, but the wait isn't unregistered until the target arrives or the
timeout elapses.
timeout must be a number greater than zero. Throws if timeout is zero,
negative, or not a number.
Roblox reference: InstanceHandle