3

I understand difference between class and struct in Swift. Now I'm wondering what to use for hierarchy model.

To define a class is pretty simple (setting connections on properties set is now irrelevant).

class XYClass {
    var title: String
    var subinstances: [XYClass]
    weak var superinstance: XYClass?
}

But it looks like pretty fine model for struct. Especially if I need to instantiate a lots of these and frequently. But I'm wondering if I can somehow safely point to superinstance or I need to store whole object graph to every instance on every change... Should I use class or struct and if struct, how to define it?

1

1 Answer 1

2

You are making a linked list. If you were to try to form a linked list of structs of a single type, memory management would not be feasible, and the compiler would stop you dead in your tracks. This won't compile:

struct XYClass {
    var title: String
    var subinstances: [XYClass]
    var superinstance: XYClass?
}

The compiler has spotted the problem. You cannot refer to an instance of a struct as a property of that struct. (The compiler calls this a "recursive value type".)

Thus, for your situation, you must use a class, because only then can you get a weak reference and avoid a retain cycle. Only a reference to a class can be weak (and only if the reference is typed as an Optional).

This will compile, and will give your linked list coherent memory management:

class XYClass {
    var title: String = ""
    var subinstances: [XYClass] = []
    weak var superinstance: XYClass?
}
Sign up to request clarification or add additional context in comments.

6 Comments

I would like to point out that one should use the prefix declaration modifier unowned instead of weak under the guaranteed presence of a logical hierarchical parent.
@VatsalManot I don't think it is guaranteed. There must be a top level (root). It has no superinstance, and we would thus have a very dangerous situation. weak is a much better choice, because we can use an Optional and have nil automatically if the referent is deallocated. This situation is not at all appropriate for unowned. Use unowned only if the referent is existentially prior and guaranteed. For example, if a class retains a function, the function can refer to the class instance as unowned because if it didn't exist there would be no one to retain the function.
I think that a dummy superinstance should be created for the root instance. As for memory management, unowned makes it easier to maintain a list, as the deallocation of one superinstance would trigger a chain collapse of all it's subinstances, eliminating the headache of memory leaks.
The dummy superinstance would itself have an unowned superinstance, so all you have done is to push the same problem back one level. And there are not going to be any memory leaks with the model I have suggested: instance retains its subinstances but not its superinstance, so there is no possibility of a retain cycle.
Use subclasses, separating the root and the children instances. The root instance should not have a super-instance. This is a more favorable (and structured) approach as opposed to the cumbersome woes of your average Optional addict.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.