How to create bridges between frameworks in an iOS app

Rayane Kurrimboccus
The Startup
Published in
5 min readApr 12, 2019
If the code of your app looks like this…

“I want to export that part of my app but it’s tied to the rest of the app like a spaghetti plate !”

Trying to export a small part of the app which is too dependent

When I was starting to modularize a part of the app I was working on, I ran into a wall.

I wanted to export a service (in fact it was the Tracking service) into a separate framework. The problem was that this service was too hardly tied to the app. It was using an other service which was itself using another deeply anchored in the app.

In order to export the tracking service, I would have had to refactor and remake the whole set of service in the new framework !

But the fact is I didn’t had the time to do this and regression testing would have been a nightmare, and for many other reasons that you could have in any company (process, budget, deadline).
So I had to find out how to export this part of my app without refactoring everything.

Let’s start with an concrete example !

Here we are, the best way to learn and to understand how things work is to practice ! (I am going to provide the Github repo for this example at the end of this post)
So let me set the context, we have a small app with only 2 screens :

  • A home screen
  • A payment screen (we want to export that screen into a framework)

The payment page contains a TextField to enter a card number, and a Pay button. When you press the button, the payment should be launched.
But ! The challenge resides in the payment method. Let’s suppose we just can’t export the payment service for some reasons I evoked a bit earlier.

Home screen and Payment screen

So we have these two screens, declared in two different targets. The home screen is declared in the main app target, and the payment screen is declared in another module called PaymentModule. We also have a PaymentService declared in the main app target, as follow :

The pay method is the method we can’t extract from the app because it is too dependent. But we want to use it from the payment module.

We have a PaymentViewController defined in the Payment module, if we try to call PaymentService we will have an error since this service is not in the module. You can’t import the main target within a module (that would be a nonsense)

So how are we going to use this method from the PaymentViewController ?

Define a protocol in the module

This is going to be our bridge. You must define a protocol in the module with a method describing what you want to use in the main app target.

So let’s define a protocol named PaymentServiceProtocol with a method pay :

Implementing the protocol in the app

Now we have to tell to our PaymentService to conform to this protocol. We just need to add this :

“Why the method declared in the protocol is not implemented in this extension ?”

You are right, when conforming to a protocol you must implement its properties and methods. The trick here is that the method name in the protocol is exactly the same as the method name in the PaymentService we declared a bit earlier. In that way, the system will know it will have to use the method pay declared in the PaymentService class when accessing the protocol method.

Linking the two parts

We must now join the two parts together.
From the HomeViewController, when we tap on the “Go to payment page” button, we are instantiating a PaymentViewController. At that time, we are going to pass it a reference to the PaymentService class, but the payment controller in the module will see it as a PaymentServiceProtocol type.

Here is the trick :

We are passing PaymentService.self and the code in the module is seeing a PaymentServiceProtocol.Type.
Now we can use call the pay method defined in the app from the module !

Using the bridge

It is now very easy to use the bridge we created :

The method didTapPayButton is called whenever you tap on the Pay button (sounds correct, right?). Check on line 23 : we are calling the pay method on the protocol reference we got from the app.

Since the PaymentService conforms to this protocol, the system will execute the code inside the method pay , which is defined in the PaymentService.swift.

In other words, we are using the method that we couldn’t call from the module at the beginning ! The bridge is now set.

Here is what it looks like when you tap on the pay button.

Using the pay method contained in the main target, from the payment module

Conclusion

To conclude, this bridging method can be used if you want to export a component of your app into a framework.

This technique will allow you to cut the noodle out of the bowl, if you are forced to export that part of your app into a framework but you can’t export the whole thing, for any reason you could have.

I think this a temporary solution, before getting out the whole component inside the framework, when you will have the time for example. (In this scenario, someday you will have to export the pay method inside the Payment module)

I admit that in a ideal world, with unicorns and fancy stuff, we would not do something like that. We would rather export the whole component, but as I said many times this is not always possible.

You can find the Github repo of this project here, don’t hesitate to check how the bridge is done and to try it by yourself.
I hope this post can help, feel free to ask any question you have in mind !

This story is published in The Startup, Medium’s largest entrepreneurship publication followed by +442,678 people.

Subscribe to receive our top stories here.

--

--