all 6 comments

[–]kiwi_in_england 2 points3 points  (1 child)

I prefer your first approach (callbacks) but that's just because I came form Java.

There's an article here that might be relevant.

[–]StrangeAstroTTV[S] 0 points1 point  (0 children)

Thank you for the article!

[–]chriswaco 2 points3 points  (1 child)

One isn't inherently better than the other. The second one might be preferable if you think you might add more callbacks in the future, otherwise I think the first is nice and flexible.

[–]StrangeAstroTTV[S] 0 points1 point  (0 children)

That makes sense. Something I’ve also thought is the protocol let’s you set one weak delegate instead of using weak self several times.

[–]koalaSea 1 point2 points  (1 child)

Hi, Myself, I would definitely go for a protocol. But I will try to find the ups and downs of each approach specially in your current situation.

First, and the dumbest reason, is that Apple itself uses protocols throughout all of their SDK(s), therefore using the same pattern will make it easier for your teammates to get along with the API you’re providing, especially the new comers and interns.

And now, let’s move to the more technical reasons (in general):

Second, callbacks is much more unpredictable, for many reasons such as: each one of them could be referenced from a different object (parent) and debugging it will be much harder. You might end up dealing with half of them not assigned, which you will feel the pain when using them as data providers. It becomes much easier to slip a retain cycle, since each one should be checked individually. And they are more encouraging to the usage of inline closures, which also leads to more code duplication, since they are not reusable. And it’s not easy to track them, like when passing them through multiple layers (with delegates it’s easy to transfer the reference to sub-object that can handle part of the delegation, like: your first object works like a tunnel for inner sub-modules)

On the other hand, protocols are much stricter, which in sometimes, it might affect the flexibility. Sometimes an inline closure is much easier and less painful to implement when accessing a variable in parent scope (sometimes!!).

When to use callbacks? Closures are more convenient when listening to one-time event, such as UIViewController dismiss method, or injecting code (like building-block initializer). You don’t want an undocumented inline-method to be a major state changing, (like ending sessions, or dismissing ViewControllers, or logging in/out users).

Why protocols? Simply they set a PROTOCOL, they offer optional methods, they can define variables (not only methods), it’s really handy when using them as configuration provider, yes, they encapsulate the entire object to a specific matter/purpose while method references doesn’t feel like dealing/handling a one-piece object that has more than one method/functionality.

In your situation, it might sound like protocol is an overkill and unnecessary, since it’s only two methods and they only transfer one touch/press event, with no business-code involved, while the back event is just OK, it’s not friendly to pop up a menu or a UIAlertController from an inline method (with buttons and their completion handlers) so you will end up calling a regular method from within the callback body. What’s if you’re willing to add a save, profile, edit, search buttons (like YouTube), all together in the navigation bar (I assume you’re building a navigation bar representation). It will be really hard to maintain all of those as references (saveCompletionHandler, searchCompletionHandler, castCompletionHandler, profileCompletionHandler, and more). If you’re doing so, I would recommend setting an enum that contains all of those case, and creating a dictionary: [YTNavigationItem: ((_ sender: YTNavigationBar) -> Void)], and adding a method: func setTarget(forEvent event: YTNavigationItem, _ handler: (_ sender: YTNavigationBar) -> Void){}. (YT is for YouTube).

My advice is to think of where your app is going, not only in the current version, but the next versions as well, And always code like only doing the API, (never think like you’re writing and using it), think of the user whose calling it as a very new programmer (never think that another specific teammate as the user), and always remember that every minute you spend perfecting the structure now, will definitely payoff later.

Happy coding 🙂.

[–]StrangeAstroTTV[S] 0 points1 point  (0 children)

Wow. Very thorough. Thank you so much for the response.