Swift 5: how to specify a generic type conforming to protocol when declaring a variable
An associated type is used when you want your protocol to work with a variety of types, think a Container
protocol that might have several methods all dealing with one contained type.
But your protocol is not that, it doesn't need to know any other types to specify the necessary behavior, so get rid of the associated type.
protocol Pipe {
func await() -> Void
func yield( to: Any, with listener: Selector ) -> Void
}
class Foo {
var imageSource: Pipe & Renderable
}
Using a Generic Type with a Protocol and associated type?
You can't have a property of type Updater
. That's abstract. You need to use it to constrain a concrete type (U
in this case).
class MyContainer<T, U: Updater> where U.UpdateType == T {
private(set) var object: T
private(set) var updater: U
}
This approach can become tedious however. The where U.UpdateType == T
clause often spreads repeatedly through code that uses MyContainer
.
Typically the solution is a type-eraser. Rather than a protocol, use a generic with closures:
struct Updater<T> {
var success: ((T) -> Void)?
var failure: ((NSError) -> Void)?
}
class MyContainer<T> {
private(set) var object: T
private(set) var updater: Updater<T>
}
Updater
of course could wrap a single update(withSuccess:withFailure:)
method instead, but splitting it up this way is often much nicer in practice.
Swift - implement protocol with generic method for different T types
The way you have it written, by conforming to the protocol Client, you have to implement a function get
, with a generic, unconstrained argument T
. In the example implementations provided, you added a type constraint to the generic parameter T
, which does not match the function in the protocol.
There's more than one way you can approach a solution to this problem. Keeping in mind that you said all entities will conform to Mockable
, the solution that requires the least change to the code you provided is to use protocol composition to enforce that all parameters T
conform to both Decodable
and Mockable
.
protocol Client {
func get<T: Decodable & Mockable>(_ url: String) -> Promise<T>
}
In your clients, you would implement that function exactly as written.
Now, in your MockClient
, you can call T.mock()
, and in your real implementations, you can treat T
as Decodable
as required. Of course, this now requires that even your mock arguments conform to Decodable
, but I would assume your mock arguments will be fairly lightweight and thus this wouldn't be a problem.
How to make a generic class conform to a protocol for specific type?
No, such construct isn't possible (circa Swift 3.1 at least).
For instance:
class SomeClass { }
protocol SomeProtocol { }
extension Matrix: SomeProtocol where T == SomeClass { }
Gives a very clear error message:
Extension of type
Matrix
with constraints cannot have an inheritance clause.
But all is not lost... as correctly noted by Alexander, there is already a proposal lined up for Swift 4! The feature will be called Conditional Conformances (SE-0143).
A nice example for all protocol-oriented programming hackers out there:
extension Array: Equatable where Element: Equatable {
...
}
If an array contains equatable elements than said array is also equatable.
Update. Swift 4 is out but this feature hasn’t landed yet. We may need to wait until Swift 5 for this...
Related Topics
Firebase Snapshot.Key Not Returning Actual Key
How to Use the Appropriate Color Class For the Current Platform
Upvote/Downvote System Within Swift via Firebase
Override Func Error in Swift 2
Should Conditional Compilation Be Used to Cope With Difference in Cgfloat on Different Architectures
How to Unittest Combine Cancellables
Swift5 Macos Imageresize Memory Issue
How to Access Nswindow from @Main App Using Only Swiftui
Remove Element from Collection During Iteration with Foreach
How to Use Contains Within a Swift Array Extension
Reading Data into a Struct in Swift
How to Get User Home Directory Path (Users/"User Name") Without Knowing the Username in Swift3
Function with Datatask Returning a Value
Reasons to Include Function in Protocol Definition VS. Only Defining It in the Extension