Types of Things in Swift
The rule is:
-
Class instances are reference types (i.e. your reference to a class instance is effectively a pointer)
-
Functions are reference types
-
Everything else is a value type; “everything else” simply means instances of structs and instances of enums, because that’s all there is in Swift. Arrays and strings are struct instances, for example. You can pass a reference to one of those things (as a function argument) by using
inout
and taking the address, as newacct has pointed out. But the type is itself a value type.
What Reference Types Mean For You
A reference type object is special in practice because:
-
Mere assignment or passing to function can yield multiple references to the same object
-
The object itself is mutable even if the reference to it is a constant (
let
, either explicit or implied). -
A mutation to the object affects that object as seen by all references to it.
Those can be dangers, so keep an eye out. On the other hand, passing a reference type is clearly efficient because only a pointer is copied and passed, which is trivial.
What Value Types Mean For You
Clearly, passing a value type is “safer”, and let
means what it says: you can’t mutate a struct instance or enum instance through a let
reference. On the other hand, that safety is achieved by making a separate copy of the value, isn’t it? Doesn’t that make passing a value type potentially expensive?
Well, yes and no. It isn’t as bad as you might think. As Nate Cook has said, passing a value type does not necessarily imply copying, because let
(explicit or implied) guarantees immutability so there’s no need to copy anything. And even passing into a var
reference doesn’t mean that things will be copied, only that they can be if necessary (because there’s a mutation). The docs specifically advise you not to get your knickers in a twist.