When creating iPhone apps you will come across times when you can use single instance of a class across an entire app. Network manager, audio player, and other classes that Apple provides are called Singletons. It is one of the design patterns used in iOS app development.
A singleton ensures that only one instance of the class exists across the entire app. One example is App Settings, and another is a connection to a database where you probably want just a single connection.
Although singletons are relatively easy to create, meaning the syntax to allow a class to be a singleton, you need to be careful how you create it to avoid tight coupling and hidden dependencies.
Singleton Class
final class NetworkManager {
static let shared = NetworkManager()
let id = UUID() // Unique ID to show it's the same instance
private init() {
print("NetworkManager instance created with ID: \(id)")
}
func getInstanceID() -> String {
return id.uuidString
}
}
This sample class above is called NetworkManager. It is marked as final so that it cannot be subclassed. By preventing subclassing, it prevents others from changing behaviour as they cannot subclass it.
Line 3 is set up as static meaning that it would be called as NetworkManager.getInstanceID() in this case. Let means its constant, and shared is the name of the constant although “shared” has become a well known name that is used.
We create another constant, a unique ID stored as id.
We have a private init method which can be empty if needed, but needs to be created to prevent more than a single instance being created.
We then have a method where we return the id as a uuidString.
SwiftUI View to Show Singleton Instance
struct ContentView: View {
var body: some View {
VStack {
Text("Main View")
.font(.title)
Text("Instance ID: \(NetworkManager.shared.getInstanceID())")
.padding()
Divider()
SubView()
SubView()
}
.padding()
}
}
struct SubView: View {
var body: some View {
VStack {
Text("Sub View")
.font(.headline)
Text("Instance ID: \(NetworkManager.shared.getInstanceID())")
.padding()
}
.background(Color.gray.opacity(0.1))
.cornerRadius(8)
.padding()
}
}
In the views above we have a SubView created at the bottom starting line 19. You will notice on line 25 we call NetworkManager.shared.getInstanceID() that initialises the NetworkManager class. We cannot initialise it with let nm = NetworkManager() because init is marked as private. We need to go through shared.
In our ContentView, line 7 also initialises the NetworkManager. This one runs first because lines 12 and 13 make a call to the SubView which is after the first initialisation. Either way, when you run the app you will see that they all share the same instanceID even though we initialise the NetworkManager three times. Well, in saying that, we get the shared instance of it.
If you have any questions about Singletons, please comment below.
Leave a Reply
You must be logged in to post a comment.