Reference type inside value type
Asked Answered
F

2

5

I am exploring Swift value types particularly structs to get a better understanding of it's uses in different scenario. I was amazed to see how enum can be used to build Binary Search Tree using indirect which introduces a thin layer of reference semantics.

enum BinarySearchTree<T: Comparable> {
  case empty
  case leaf(T)
  indirect case node(BinarySearchTree, T, BinarySearchTree)
}

Now coming to real question, what I am struggling to find is, what will happen to reference type inside a value type. How will the relationship work? like memory management, Object lifecycle.

For e.g.

class B {
    var data: Int = 0

    deinit {
        print("deallocated!")
    }

}

struct A {
    var b = B()
}

In the above case, a value type holds a reference to a reference type.

  1. When will deinit will get called?
  2. Does every new struct instance of type A will have reference to same instance of class B or will they be different.
  3. What should I need to take care of or it is a code smell?
  4. Anything else?
Fallible answered 4/4, 2017 at 22:5 Comment(1)
Consider that a reference itself is a value type – it (but not the instance it points to) gets copied when you pass it about. So you're already somewhat familiar with the semantics :)Shortcoming
O
6

Every struct A copy will share the same reference to B. Every new struct A, created from scratch, will hold a completely new B object.

The B.deint will be called when there are zero strong references to it (e.g., your var b is one of these strong references). For instance, if only A values hold references to a given B object then those will need to got out of scope to zero all references to this object (or their boxed copies be deallocated as well, but this might be a topic for another question.)

Code Design. If these all sounds too confusing and is blocking your app progress (with no real practical benefit so far), you might consider refactoring B to a struct as well. For instance, even Apple recommends considering value types to design your model layer. This blog post might also help make up your mind.

Outvote answered 4/4, 2017 at 22:38 Comment(2)
How to make a value go out of scope after creating it?Fallible
@Fallible For instance, if you declare a var a: A = ... inside a function, then when that function returns the a value will go out of scope. Makes sense?Outvote
K
3

You can test this in a playground:

class B {
    var data: Int = 0

    deinit {
        print("deallocated!")
    }
}

struct A {
    var b = B()
}

var a1: A? = A()
var a2: A? = A()
var a3: A? = a1

// Do the two instances of struct A share the same instance of class B?
a1?.b === a2?.b // false

// Do copies of instances of struct A share the same instance of class B?
a1?.b === a3?.b // true

// When will deinit be called?
a1 = nil    // Not yet, a3 still holds a strong reference to the shared instance of class B
a3 = nil    // Now! There are no longer any strong references to the shared instance of class B, so it is deallocated.
Kehr answered 4/4, 2017 at 22:46 Comment(3)
Are the instances of class B the same? => Only because you allocated 2 new A instances. If a2 was created by copying from a1 (via assignment), then they'll reference the same b.Unblown
Now you'll need to nil out a3, because it contains a strong reference that will preserve a1's b, even after a1 is nilUnblown
Thanks @Alexander! My mistake - I hope this answer is useful despite its edits.Kehr

© 2022 - 2024 — McMap. All rights reserved.