Encapsulating highly reusable code into a static library not only decouples the code, but also improves its maintainability. My company’s iOS project was developed using modularity, where a lot of reusable code was packaged into static libraries.
Circular references to static libraries
Consider this scenario
A Framework references B Framework, and B Framework needs to use A service in A Framework. Unfortunately, the service is coupled to the A Framework, so to avoid reference loops, we need to refactor the A Framework and migrate the service to another C Framework.
I believe that in reality, no programmer is willing to take the risk of refactoring A Framework code and unit tests (I might as well have played more with that time).
Use Protocol to resolve circular references
Here I offer an idea to help you expose services in Framework A to Framework B without refactoring existing code.
The sample code can be downloaded at the Github link at the end of this article
The preparatory work
In our main project, we defined a Color service
protocol ColorLayer {
func backgroundColor(a) -> UIColor
}
class ColorService: ColorLayer {
func backgroundColor(a) -> UIColor {
return .red
}
}
Copy the code
Let’s create a new static library and name it BridgeTestFramework
In this static library, we have a piece of code that looks like this.
public class BridgeViewController: UIViewController {
let colorService = ColorService(a)public override func viewDidLoad(a) {
super.viewDidLoad()
view.backgroundColor = colorService.backgroundColor()
}
}
Copy the code
The compiler gives an error because the BridgeTestFramework is referenced by the main project, and the BridgeTestFramework cannot reference the main project.
inBridgeTestFramework
Defined in the Protocol
Copy the Protocol of ColorService into the BridgeTestFramework. Don’t forget to minor change the name of the Protocol and change its access to public.
public protocol BridgeTestFrameworkColorLayer {
func backgroundColor(a) -> UIColor
}
Copy the code
Now let’s refactor the BridgeViewController
public class BridgeViewController: UIViewController {
let colorService: BridgeTestFrameworkColorLayer
public init(colorService: BridgeTestFrameworkColorLayer) {
self.colorService = colorService
super.init(nibName: nil, bundle: nil)}required init? (coder aDecoder:NSCoder) {
fatalError("init(coder:) has not been implemented")}public override func viewDidLoad(a) {
super.viewDidLoad()
view.backgroundColor = colorService.backgroundColor()
}
}
Copy the code
Here we use the type of attribute colorService BridgeTestFrameworkColorLayer instead. Because BridgeTestFrameworkColorLayer and ColorService exposed by the interface is the same, so we can use normal backgroundColor () this method.
Implement Protocol in the main project
Then we go back to the main project code. Introduce the BridgeTestFramework for ColorService and extend ColorService.
import BridgeTestFramework
protocol ColorLayer {
func backgroundColor(a) -> UIColor
}
class ColorService: ColorLayer.BridgeTestFrameworkColorLayer {
func backgroundColor(a) -> UIColor {
return .red
}
}
Copy the code
Because ColorLayer BridgeTestFrameworkColorLayer defined by the interface is the same, so we don’t need to change the concrete implementation ColorService.
Using the Protocol
Let’s then try to use our refactored BridgeViewController in the main project.
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let bridgeVC = BridgeViewController(colorService: ColorService())
present(bridgeVC, animated: true, completion: nil)}}Copy the code
Because ColorService BridgeTestFrameworkColorLayer the agreement is achieved, BridgeViewController can normally use the ColorService implementation of the backgroundColor() interface.
summary
In this small Demo we use Protocol to create a temporary bridge between two static libraries. Protocol allows us to share certain services between static libraries that already have dependent references without circular references.
But keep in mind that good design patterns are the ultimate solution to avoid such circular references. The Demo source code can be downloaded here.