Nested Protocols
How to put a protocol into a namespace
Yesterday my friend who has been transfered from iOS team to Android team showed me something he thinks is really cool in Java and he would love to see in Swift. He showed me that there is a possibility to put an interface declaration inside a class. In Swift it means - put a protocol definition inside a struct, class or enum definition.
Unfortunately, according to the Swift documentation:
Swift enables you to define nested types, whereby you nest supporting enumerations, classes, and structures within the definition of the type they support.
It means that currently in Swift there is no way to define a nested protocol. In other words - protocols are valid at file scope only.
But why would it be nice to have anyway? - you may ask. Imagine you could write a code like this:
// Please remember that this code won't compile.
class FileInformationProvider {
protocol Delegate: class { }
weak var delegate: Delegate?
}
If you would like to create a class which conforms to that protocol, you would write:
class FileManager: FileInformationProvider.Delegate { }
I’m sure you can see an advantage of this approach. There is no need to create a protocol called FileInformationProviderDelegate
which is declared out of FileInformationProvider
namespace. Having a nested protocol limits it inside a type to which it refers directly to. It gives more clarity to our code without a need of wondering which specific class uses this delegate protocol.
In Swift it’s very common practice to create a nested struct
or enum
to store all constants, states or keys used within a specific scope. For example:
class InformationFetcher {
struct Constants {
static let baseURL = "http://mateuszkarwat.com"
}
}
So how can we achieve the same namespacing with protocols? I came up with one solution. It involves a typealias
keyword. The typealias
keyword introduces a named alias of an existing type into your program1. Here is what we can do:
protocol FileInformationProviderDelegate { }
class FileInformationProvider {
typealias Delegate = FileInformationProviderDelegate
weak var delegate: Delegate?
}
Our code compiles now and we can conform to nested protocol by calling FileInformationProvider.Delegate
just as we wanted. It doesn’t hide FileInformationProviderDelegate
declaration though, so the protocol is still accessible outside FileInformationProvider
namespace. However, with this approach we can go further and for example create nested protocols like .DataSource
in our table view controllers.
Is this any better than just:
class FileInformationProvider {
weak var delegate: FileInformationProviderDelegate?
}
I don’t know. I guess it’s totally up to you. You might say that this solution requires a bit more code to write and probably looks like some kind of a workaround. It’s absolutely true. I’m not a big fan of it either and I probably won’t use it. The goal here was to show you there is a way to create a “nestedish” protocol in Swift in case you desperately need it.
If you come up with better solution, please let me know. I would love to try it out.