How to pass Swift Array by reference (without using NS(Mutable)Array)

I have two objects (Child1, Child2) that are supposed to write values (UInt8) into the same Array<UInt8>. For this, there is one object (Parent) that owns both these children. This parent creates an Array<UInt8> and sets this array as a property on Child1 and Child2, like so:


class Child
{
    var values: [UInt8] = []

    func changeAValue()
    {
        values[2] = 42
    }
}
class Parent
{
    var sharedValues: [UInt8] = []
    let child1 = Child()
    let child2 = Child()
    init()
    {
        sharedValues = [1,2,3,4,5]
        child1.values = sharedValues
        child2.values = sharedValues

        child1.changeAValue()

        print("Child1:\t\(child1.values)")
        print("Child2:\t\(child2.values)")
        print("Parent:\t\(self.sharedValues)")

    }
}


The output here is:

Child1: [1, 2, 42, 4, 5]
Child2: [1, 2, 3, 4, 5]
Parent: [1, 2, 3, 4, 5]


I would like that these values are shard between these objects, so that the output would be ` [1, 2, 42, 4, 5]` for all three print statements. Of course I could use an NSMutableArray, but I am interested to know what would be a nice (and performant!) way to do this in pure Swift.

My (maybe naive?) idea is to just write a wrapper class for an Array, but this seems like a problem that smarter minds then me have already thought about and figured out the best solution for .


What is the best (most performant and generic) way to do this?

Your problem is that sharedValues is passed by value, not by reference.


A way to achieve what you want is to make it a class, hence it will be passed by reference.


I tested this in Playground


class ValueClass {
    var values: [UInt8] = []
}

class Child
{
    var childValues: ValueClass /
   
    init()
    {
        childValues = ValueClass()
    }
   
    func changeAValue()
    {
        childValues.values[2] = 42
    }
}
class Parent
{
    var sharedValues = ValueClass() /
    let child1 = Child()
    let child2 = Child()
    init()
    {
        sharedValues.values = [1,2,3,4,5]
        child1.childValues = sharedValues
        child2.childValues = sharedValues
       
        child1.changeAValue()
       
        print("Child1:\t\(child1.childValues.values)")
        print("Child2:\t\(child2.childValues.values)")
        print("Parent:\t\(self.sharedValues.values)")
       
    } 
}
let x = Parent()


PS: Why do you want 2 objects (child1 and child2) if they have the same value ?

"Your problem is that sharedValues is passed by value, not by reference."

I know this.


Both Child1 and Child2 read from and write to this array (synchronously, no race conditions possible). To avoid having to write a number of functions that pass back and forth a (very sizable) array, I want this array to be a shared resource.

Also, in the grand scheme of my app I would like this array to actually be an array ([UInt8]), so it can live among other variables that are of type [UInt8], and I get to factor out some code that operates on those kind of arrays.


One option I see is to write a class that wraps Array, but then I would have to implement all protocols that Array conforms to and forward the functions to an internal property that is of type [UInt8]. This seems tedious and requires me to also use this class in places where I don't really need reference semantics, just so I get to factor out some common stuff (which I can only do if a number of variables in Parent where of the same type).

Another option is to use NS(Mutable)Array (for all of those properties on Parent ), but this seems like a loser's option, as it is falling back onto Objective-C.


For now, I will go with your solution. It feels a kind of clumsy, but it seems that is the Swift way of doing things and the best we can get. Thank you for your suggestion!

You could also use pointer, in order to write :


child1.values = &sharedValues

Here's one solution:


typealias Value = UInt8


class Child
{
    unowned let parent: Parent
   
    var values: [Value]
    {
        get { return parent.sharedValues }
        set { parent.sharedValues = newValue }
    }
   
    init(parent: Parent)
    {
        self.parent = parent
    }
   
    func changeAValue()
    {
        values[2] = 42
    }
}


class Parent
{
    var sharedValues: [Value]

    private(set) var child1: Child!
    private(set) var child2: Child!
   
    init()
    {
        sharedValues = [1, 2, 3, 4, 5]
        child1 = Child(parent: self)
        child2 = Child(parent: self)

        child1.changeAValue()

        print("Child1:\t\(child1.values)")
        print("Child2:\t\(child2.values)")
        print("Parent:\t\(sharedValues)")
    }
}


_ = Parent()



The output is:


Child1: [1, 2, 42, 4, 5]
Child2: [1, 2, 42, 4, 5]
Parent: [1, 2, 42, 4, 5]

This is a very convenient solution.

However I don't think a Child should now about the type of their Parent, so for this to be nice I would have to set up some protocol, e.g. ValuesVendor, that has only one property:

protocol ValuesVendor
{
     var values: [UInt8] { get }
}

Then Parent should conform to this protocol, and Child would have a property of type ValueVendor, instead of Parent.


I think I will go with this solution, but I still feel like there should be a less clumsy and more transparent way to do this.

You'll probably have to define ValuesVendor like:


protocol ValuesVendor: class 
{ 
    var values: [UInt8] { get set } 
}

If the Parent is a singleton, you could make the shared UInt8 array a global variable, and pre-allocate space for it in the Parent using:


sharedValues = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(sizeOfSharedValuesArray))
How to pass Swift Array by reference (without using NS(Mutable)Array)
 
 
Q