AppsDev
AppsDev

Reputation: 12509

Completion handler VS holding a reference: the most appropriate for this scenario in Swift?

I have the following scenario: an object A creates an object B that should perform some operations depending on a user's choice. A is delegate of B. A does not hold a reference to the choice the user has made (represented by another object C), but it knows it in the method where it creates B, and it needs to know which the choice was when the object B finishes its task and notifies of that by calling the corresponding protocol method that A implements.

The first solution I think of for this scenario is to have a reference in A for the choice C, and access it in the protocol method implementation that B calls when it finishes. But maybe it would be better and more "swifty" to handle such choice C by passing a completion handler, and thus avoiding holding a reference in A until B finishes.

What do you think about this second solution (to pass a closure as completion handler to B)? Would it be more appropriate than the first solution (holding a reference in A)?

In such case, how should I implement that solution? Should B have a reference for the closure to be called as completion handler?

EDIT: Some additional information of my scenario:

Upvotes: 1

Views: 246

Answers (1)

Sulthan
Sulthan

Reputation: 130152

In short, in your ownership hierarchy A owns B, both classes use C and you want to know whether C should be owned by A or B.

You have 3 basic options:

  1. Both A and B own C.

That means that A saves C into a property, passes it to B during initialization and B also saves C to a property.

  1. A owns C.

That means that A saves C into a property and doesn't pass it to B at all. B asks for it using a delegate method when it needs it (A serves as data source for B).

  1. B owns C.

That means A passes C directly to B, B saves it to a property with a public getter and when A needs C, it reads it from B.

(Note your idea is a variant of the third option).

Note that neither of the three options has anything to do with swiftiness, it's purely an architecture choice and there is no "best" solution. If you want to decide, you have to consider the states of your application, for example:

  1. Should C exist in A even after B is destroyed? If yes, don't use the 3rd option.

  2. Does A handle multiple B or C at once? Then don't use the second option.

  3. Is C mutable or immutable? Is it a value or class type? If it's a value type, you cannot use the first option.

In most situations all 3 options above will be fine and the choice will be a personal decision that won't affect the quality of your code if you keep it consistent across your application.

EDIT:

It seems to me that the 3rd option is really the most appropiate solution for your situation. However, as I said before, there is not one "best" solution

Upvotes: 1

Related Questions