How to use generic protocol in the method signature?
You can't use a protocol with associated types like that. Protocols with associated types are not the same as generic protocols. The latter does not exist in Swift.
What you usually do in this situation is to introduce a new generic parameter, U
to the method and constrain that to the protocol:
func show<T, U>(a: U) where T: Decodable, U : AProtocol, U.T == T {
}
The 3 constraints are:
T
must conform toDecodable
U
must conform toAProtocol
U.T
must be the same asT
Makes sense, right?
Swift 2.0: Protocol extensions: Two protocols with the same function signature compile error
A protocol defines requirements (methods, properties, ...) for a
conformant type.
protocol FirstDelegate {
func someFunc()
}
protocol SecondDelegate {
func someFunc()
}
defines two protocols with the same required method someFunc()
.
A conformant type must implement this method:
class SomeClass: FirstDelegate, SecondDelegate {
func someFunc() {
print("SomeClass implementation")
}
}
A protocol extension provides method and property implementations
to conformant types. A special case of a protocol extension is a
default implementation, which is what you defined here:
extension FirstDelegate {
func someFunc() {
print("First delegate")
}
}
It defines a default implementation of someFunc()
for all types
conforming to FirstDelegate
. Since this is the only required
method of that protocol, a conforming class need not define the
method at all:
class SomeClass: FirstDelegate {
}
SomeClass().someFunc() // Output: First delegate
But if the class provides its own implementation then that
will be used:
class SomeClass: FirstDelegate {
func someFunc() {
print("SomeClass implementation")
}
}
SomeClass().someFunc() // Output: SomeClass implementation
In your case, you have defined default implementations of someFunc()
for both protocols:
extension FirstDelegate {
func someFunc() {
print("First delegate")
}
}
extension SecondDelegate {
func someFunc() {
print("Second delegate")
}
}
A class can still conform to both protocols if it provides its own
implementation of the required method:
class SomeClass: FirstDelegate, SecondDelegate {
func someFunc() {
print("SomeClass implementation")
}
}
But the class cannot conform by using the default implementation
class SomeClass: FirstDelegate, SecondDelegate {
}
for both protocols
because there is a conflict. It is unspecified which default
implementation should be used, and that's why the compiler complains.
Actually the class now conforms to none of the protocols.
This can be seen in the full compiler log in the Report navigator:
main.swift:24:7: error: type 'SomeClass' does not conform to protocol 'FirstDelegate'
class SomeClass: FirstDelegate, SecondDelegate {
^
main.swift:5:10: note: multiple matching functions named 'someFunc()' with type '() -> ()'
func someFunc()
^
main.swift:19:10: note: candidate exactly matches
func someFunc() {
^
main.swift:13:10: note: candidate exactly matches
func someFunc() {
^
main.swift:24:7: error: type 'SomeClass' does not conform to protocol 'SecondDelegate'
class SomeClass: FirstDelegate, SecondDelegate {
^
main.swift:9:10: note: multiple matching functions named 'someFunc()' with type '() -> ()'
func someFunc()
^
main.swift:19:10: note: candidate exactly matches
func someFunc() {
^
main.swift:13:10: note: candidate exactly matches
func someFunc() {
^
Conform to protocol in ViewController, in Swift
You use a comma:
class GameList: UIViewController, UITableViewDelegate, UITableViewDataSource {
// ...
}
But realize that the super class must be the first item in the comma separated list.
If you do not adopt all of the required methods of the protocol there will be a compiler error. You must get all of the required methods!
iOS11 Swift 4 - how to check if Swift class conforms to protocol defined in Objective-C?
[MyClass conformsToProtocol:@protocol(MyProtocol)];
According to Apple Docs you can use conformsToProtocol:
which returns a Boolean value that indicates whether the receiver conforms to a given protocol.
Example
@protocol MyProtocol
- (void)helloWorld;
@end
@interface MyClass : NSObject <MyProtocol>
@end
Will be exposed as:
console.log(MyClass.conformsToProtocol(MyProtocol));
var instance = MyClass.alloc().init();
console.log(instance.conformsToProtocol(MyProtocol))
ios swift class conforming protocol
Your issue is that while you can add protocol conformance via an extension, the extension is applied to the class, not an instance of that class. This means that you can say something like:
extension UITextField: ValidatesName {...}
But this will make all instances of UITextField conform to ValidatesName
Similarly, you could also say
extension UITextField: ValidatesEmail{...}
But now all instances of UITextField will conform to ValidatesName
and ValidatesEmail
.
Having separate Validates...
protocols doesn't seem like the right approach anyway. The basic signature of your protocol is something like var isValid: Bool
; this doesn't change between name and email. What does change is the validation logic and this has to live somewhere. This, coupled with the fact that you need subclasses in order to work with Interface Builder would suggest that a single protocol Validatable
that can be adopted by your various subclasses is a more reasonable approach.
protocol Validatable {
var isValid: Bool { get }
}
Now, you can define subclasses of UITextField that conform to this protocol (You can add the conformance via an extension to your subclass if you like, I just wanted to save space here)
class NameTextField: UITextField, Validatable {
var isValid: Bool {
get {
guard let text = self.text else {
return false
}
return !text.isEmpty
}
}
}
class EmailTextField: UITextField, Validatable {
var isValid: Bool {
get {
guard let text = self.text else {
return false
}
return text.contains("@")
}
}
}
Now, you can add your textfields to an array, and have something like:
@IBOutlet weak var nameTextField:NameTextField!
@IBOutlet weak var emailTextField:EmailTextField!
var validatableFields:[Validatable]!
override func viewDidLoad() {
super.viewDidLoad()
self.validatableFields = [nameTextField,emailTextField]
}
...
for field in validateableFields {
if !field.isValid() {
print("A field isn't valid")
}
}
Swift transitive protocol conformance
The reason that it doesn't work
Assuming your code would work and we write additionally
class ExampleCoordinator2: Coordinator {}
val viewController = ViewController()
viewController.coordinator = ExampleCoordinator2()
The assignment to coordinator
cannot work since ExampleCoordinator2
is not a subclass of ExampleCoordinator
.
So, just considering the types the following code should work but the Swift compiler doesn't allow it (this might work in the future):
protocol Coordinatable {
var coordinator: Coordinator { get } // removing the `set`
}
class ViewController: UIViewController, Coordinatable {
var coordinator: ExampleCoordinator! // still an error
}
Possible solutions
Using var coordinator: Coordinator
in ViewController
class ViewController: UIViewController, Coordinatable {
var coordinator: Coordinator
init(coordinator: Coordinator) {
self.coordinator = coordinator
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Using only { get }
in Coordinatable
protocol Coordinatable {
var coordinator: Coordinator { get } // removing the `set`
}
class ViewController: UIViewController, Coordinatable {
// computed property
var coordinator: Coordinator {
// implicit return
exampleCoordinator
}
var exampleCoordinator: ExampleCoordinator!
}
Using an associatedtype
in Coordinatable
protocol Coordinatable {
associatedtype C: Coordinator
var coordinator: C { get set }
}
class ViewController: UIViewController, Coordinatable {
var coordinator: ExampleCoordinator
init(coordinator: ExampleCoordinator) {
self.coordinator = coordinator
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
This has however a big disadvantage that you cannot have a heterogenous array of type [Coordinatable]
since Coordinatable
has an associatedtype
. And still, you cannot assign a value of type ExampleCoordinator2
.
You can only write generic code over <C: Coordinatable>
. E.g.
func printCoordinators<C: Coordinatable>(coordinatables: [C]) {
coordinatables.forEach {
print($0.coordinator)
}
}
Related Topics
How to Submit Swift 2.2 App with Xcode 7.3 When iOS 10 Is Released
Tap Gesture Not Working as Expected When Added to Uiview in Collectionview Cell
Make a Grid of Buttons of Same Width and Height in Swiftui
Formula to Pick Every Pixel in a Bitmap Without Repeating
Override Multiple Overloaded Init() Methods in Swift
Swift Cannot Assign to Self in a Class Init Method
How to Convert an Anykeypath to a Writablekeypath
Why Specializing a Generic Function Explicitly Is Not Allowed
Swift Error with Generic Array
Swiftui Button Interact with Map
How to Add an Uicollectionviewlayout Programmatically
Is It Safe to Force Unwrap an Optional After Checking It Is Not Nil
Infer Closure Return Type from Closure Body When Working with Generics
Change Notification from Observable Object as a Nested Object in Swiftui
Type of Expression Is Ambiguous Without More Context in Xcode 11