How to add reactive-ness to Clean Swift

I answered different forms of this same questions many times in emails, comments, and my mentorship program. I understand why people ask this question. They’ve seen MVVM, ReactiveCocoa, RxSwift, and want to see if Clean Swift can handle this model-view update automatically.

My answer is always the same. You don’t need it. You don’t need to add yet another dependency just to do this simple thing.

Your interactor can invoke a method of the presenter multiple times, and/or invoke multiple methods of the presenter.

The following is taken directly from a discussion in my mentorship program.

Invoke multiple presenter methods for different success/failure conditions

When you start some async work, sometimes it’s necessary to show a loading status to the user. Would you prefer the VC changes itself to the loading status when it calls the interactor to do the async work? Or the interactor sends a start loading message to the presenter when it starts the async work?

So far I have been implementing the second option, but it happens that one interactor use case calls two (or three) different presenter use cases (start loading, stop loading, present result from async work)

Yes, you’re absolutely right. There isn’t a strict 1-to-1 relationship for use cases between the VIP components. It’s flexible and you’re in control of how you want to break it down. For example, I could do something like this:

I call presentFetchProgress(response:) immediately after starting the async work and before the function returns to show a start loading message. I also call presentFetchProgress(response:) to report progress, as long as the worker supports it. When it’s done, I call presentFetchedPosts(response:) to format the list of posts. If there’s an error, I call presentFetchError(response:) to alert the user.

So, 1 interactor method can potentially call 4 presenter/view controller methods. This is a very good way to break it down for each situation, especially there’s a lot of work you have to do to handle the different conditions.

Alternatively, you can just have 1 presenter/view controller method. But then you’ll have to handle all cases in one function. It’s entirely up to you how you want to design it.

When you buy The Clean Swift Handbook, you’ll get a one-month trial to the mentorship program, where you’ll receive personal advice and answers to your questions about Clean Swift.

Raymond
I've been developing in iOS since the iPhone debuted, jumped on Swift when it was announced. Writing well-tested apps with a clean architecture has been my goal.

4 Comments

  1. Hi Raymond,

    I saw that you use the same Response object for mutiple presenters:

    Ex1: let response = Feed.FetchPosts.Response(progress: progress)
    Ex2: let response = Feed.FetchPosts.Response(posts: posts)

    Could you explain a little bit more how do you do that? Are you implementing custom init’s at the response object and adding default (or nil) values to the other parameters that are not necessary for that specific presenter method?

    1. Hi Victor,

      Good observation! Yes, if you use the same response object without initializing all the members in the struct, you need custom initializers to set the other members. If not, when you create the response object with the default initializer, you need to set the other members to nil explicitly.

      Alternatively, you can use a different response object. In the example of this post, you can have a Feed.FetchPostsSuccess.Response, Feed.FetchPostsProgress.Response, and Feed.FetchPostsError.Response. That’s a design decision up to you.

  2. Hi Raymond,

    I think this approach is good.
    What is your opinion?

    1. Hi Ukjeong,

      You can certainly define different models and methods for different kinds of responses, if a success and error variables don’t work for you.

Leave a Comment

Your email address will not be published. Required fields are marked *