Class conforming protocol throws "cannot conform to" class error - swift

protocol AClass: class {
}
class Controller {
let classes: [AClass] = []
init() {
self.upload(classes: self.classes)
}
func upload<C: AClass>(classes: [C]) {
}
}
The line in the initializer has a compile-time error of:
Value of protocol type 'AClass' cannot conform to 'AClass'; only struct/enum/class types can conform to protocols
Why? The protocol can only be applied to a class. Do I need to tell the compiler something more?

When using generics (func upload<C: AClass>(classes: [C])), you ask for a generic type that conform to the protocol AClass.
However, in Swift a protocol doesn't conforms to itself, so using classes (which is AClass protocol) doesn't match the generic requirement (conforming to AClass).
In your case, I don't see the benefit of using a generic for the upload method. You can just use AClass protocol here:
class Controller {
let classes: [AClass] = []
init() {
self.upload(classes: self.classes)
}
func upload(classes: [AClass]) {
// here you can use any property / method defined in `AClass` protocol.
}
}

Related

AnyObject and generics in Swift

This code fails to compile with Swift 5.1
import Foundation
protocol SomeClassProtocol: AnyObject {}
class SomeClass: SomeClassProtocol {}
class GenericClass<T:AnyObject> {
weak var t: T?
init(t: T) {
self.t = t
}
}
let test = GenericClass<SomeClassProtocol>(t: SomeClass())
The error is
'GenericClass' requires that 'SomeClassProtocol' be a class type
Does the compiler really need a class type here instead of a class-only protocol?
Yes. Though the syntax is the same (a colon), protocol inheritance is not the same thing as protocol conformance. Protocols do not conform to protocols; only types can conform to protocols. (AnyObject is not special in this regard; your question is good but the title isn't getting at the issue.)
In your example:
Your T needs to conform to AnyObject. SomeClassProtocol does not conform to AnyObject. But any types that conform to SomeClassProtocol will conform to AnyObject.
So you need to pick which of these you really want:
1.
let test = GenericClass( t: SomeClass() )
(test is a GenericClass<SomeClass>.)
2.
class Class {
weak var object: AnyObject?
init(object: AnyObject) {
self.object = object
}
}
Class( object: SomeClass() )
You do have the option of subclassing, if that would be useful.
class GenericClass<T: AnyObject>: Class {
var t: T? {
get { object as? T }
set { object = newValue }
}
}
Does the compiler really need a class type here instead of a class-only protocol?
Yes, it does. I think the problem is just understanding what this means:
class GenericClass<T:AnyObject>
That means: "To resolve GenericClass, the parameterized type T must be some type that is a class." Examples would be UIView, NSString, etc.
Okay, so:
let test = GenericClass<SomeClassProtocol>(t: SomeClass())
So, SomeClassProtocol is none of those; it isn't the name of a class. It's the name of a protocol.
A further difficulty may be understanding protocols as types. They are not really full-fledged types.
You don't need to specify T explicitly.
Change your code from this:
let test = GenericClass<SomeClassProtocol>(t: SomeClass())
To this:
let test = GenericClass(t: SomeClass())

How to cast to protocol type in a class?

This is my code:
protocol ProtocolA {
static var myProperty: Int { get }
}
protocol ProtocolB {}
extension ProtocolB {
func letsDoSomething() {
(Self.self as! ProtocolA.Type).myProperty // Works
}
}
class MyClass {
func castSelfToProtocolAType() {
(Self.self as! ProtocolA.Type).myProperty // Doesn't work
(Self as! ProtocolA.Type).myProperty // Doesn't work also
}
}
How can I cast self in MyClass to the dynamic type (like in the protocol extension) ProtocolA.Type?
As per your question,
You are trying to convert your class instance to the protocol type instance, which is not possible because your class does not conform to that protocol.
The direct casting from class/struct instance to protocol type
instance is not possible, you can only convert to protocol type by
accepting that class/struct as a method parameter or by assigning to the other property which protocol type, this is known as
implicit type casting.
Please read this article to understand more about protocols and class types
https://medium.com/swift-india/protocol-the-power-of-swift-5dfe9bc41a99
https://medium.com/swift-india/protocol-the-power-of-swift-950c85bb69b1
https://medium.com/swift-india/protocol-the-power-of-swift-45e97f6531f9
https://medium.com/#hitendrahckr/protocol-the-power-of-swift-6906cdedd867
https://medium.com/swift-india/protocol-the-power-of-swift-1e5b86bfd1dc

Swift protocol error: 'weak' cannot be applied to non-class type

What's the difference between Protocols and class-bound Protocols, and which one we should use in Swift?
protocol A : class { ... }
protocol A { ... }
We get an error when attempting to add a weak delegate when the Protocol is not defined as : class:
protocol A { ... }
weak var delegate: A
Gives the error:
'weak' cannot be applied to non-class type
or
'weak' must not be applied to non-class-bound 'A'; consider adding a protocol conformance that has a class bound
Swift >= 4:
protocol A : AnyObject { ... {
Swift < 4:
protocol A : class { ... }
defines a "class-only protocol": Only class types (and not structures or enumerations) can adopt this protocol.
Weak references are only defined for reference types. Classes
are reference types, structures and enumerations are value types.
(Closures are reference types as well, but closures cannot adopt
a protocol, so they are irrelevant in this context.)
Therefore, if the object conforming to the protocol needs to be stored in a weak property then the protocol must be a class-only protocol.
Here is another example which requires a class-only protocol:
protocol A {
var name : String { get set }
}
func foo(a : A) {
a.name = "bar" // error: cannot assign to property: 'a' is a 'let' constant
}
This does not compile because for instances of structures and enumerations, a.name = "bar" is a mutation of a. If you define
the protocol as
protocol A : class {
var name : String { get set }
}
then the compiler knows that a is an instance of a class type to that
a is a reference to the object storage,
and a.name = "bar" modifies the referenced object, but not a.
So generally, you would define a class-only protocol if you need
the types adopting the protocol to be reference types and not value types.
If you are using Swift 4 or later, use AnyObject:
protocol A : AnyObject { ... }
Using class as before gives the warning and fix-it:
Using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead
Replace 'class' with 'AnyObject'
You can make the protocol derive from any class type like NSObject or AnyObject:
protocol TopNewsTableDelegate : AnyObject {
func topNewsTableDidLoadedStories()
}
Or you can type like this
#objc protocol A { ... }
then you can make a weak delegate reference
protocol CustomProtocolName : NSObjectProtocol {
// ...
}

Further constraining a generic function from a Swift Protocol

I have a Swift protocol defined like this:
protocol MyProtocol {
func genericMethod<T:MyProtocol>(param:T) -> ()
}
I can implement the generic method in a base class like this:
class MyBaseClass : MyProtocol {
func genericMethod<T where T:MyProtocol>(param:T) -> () {
println("Performing generic method for type \(T.self)")
}
}
class MySubClass : MyBaseClass {
...
}
So far, so good. I can implement this method and it compiles and runs just fine.
Now, I want to do something similar but in my base class I want to further constrain the type of the generic method by requiring it to conform with a protocol such as Comparable. I try this:
class MyBaseClass : MyProtocol {
func genericMethod<T where T:MyProtocol, T:Comparable>(param:T) -> () {
println("Performing generic method for type \(T.self)")
}
}
Once I add this additional constraint on type T, the class MyClass will not compile because it does not conform to the protocol anymore.
It seems like adding an additional constraint on a generic type should not cause it to cease conforming with a protocol. What am I missing? It seems to me that the protocol is saying that genericMethod must be passed a parameter of a type that conforms with MyProtocol. When I go to implement this in MyBaseClass - just one possible implementation of MyProtocol - that I should be able to restrict that implementation further by saying that the parameter myst conform with Comparable in addition to MyProtocol
Is there a way to refine a generic type in a base implementation like I'm trying to do here?
Adding the additional constraint on a generic type should cause it to cease conforming with the protocol because the protocol is supposed to guarantee conformance, and conformance cannot be guaranteed with subtypes that aren't Comparable. If you want all MyProtocol objects to conform to Comparable then you should make it part of the MyProtocol definition.
protocol MyProtocol: Comparable {
//...
}
I haven't tried this, but it might also work if you make MyBaseClass a Comparable type.
One solution is to go the other way - define your protocol's version of the generic as the most restrictive case. This compiles:
protocol P {
func genericMethod<T where T:P, T:Comparable>(param:T) -> ()
}
class C1 : P {
func genericMethod<T> (param:T) -> () {} // compiles even though omits Comparable
func test() {
genericMethod(C1()) // compiles even though C1 is not a Comparable
}
}

How do I specify that a non-generic Swift type should comply to a protocol?

I'd like to implement a Swift method that takes in a certain class type, but only takes instances of those classes that comply to a specific protocol. For example, in Objective-C I have this method:
- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter;
where GPUImageOutput is a particular class, and GPUImageInput is a protocol. Only GPUImageOutput classes that comply to this protocol are acceptable inputs for this method.
However, the automatic Swift-generated version of the above is
func addFilter(newFilter: GPUImageOutput!)
This removes the requirement that GPUImageOutput classes comply with the GPUImageInput protocol, which will allow non-compliant objects to be passed in (and then crash at runtime). When I attempt to define this as GPUImageOutput<GPUImageInput>, the compiler throws an error of
Cannot specialize non-generic type 'GPUImageOutput'
How would I do such a class and protocol specialization in a parameter in Swift?
Is swift you must use generics, in this way:
Given these example declarations of protocol, main class and subclass:
protocol ExampleProtocol {
func printTest() // classes that implements this protocol must have this method
}
// an empty test class
class ATestClass
{
}
// a child class that implements the protocol
class ATestClassChild : ATestClass, ExampleProtocol
{
func printTest()
{
println("hello")
}
}
Now, you want to define a method that takes an input parameters of type ATestClass (or a child) that conforms to the protocol ExampleProtocol.
Write the method declaration like this:
func addFilter<T where T: ATestClass, T: ExampleProtocol>(newFilter: T)
{
println(newFilter)
}
Your method, redefined in swift, should be
func addFilter<T where T:GPUImageOutput, T:GPUImageInput>(newFilter:T!)
{
// ...
}
EDIT:
as your last comment, an example with generics on an Enum
enum OptionalValue<T> {
case None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)
Specialized with protocol conformance:
enum OptionalValue<T where T:GPUImageOutput, T:GPUImageInput> {
case None
case Some(T)
}
EDIT^2:
you can use generics even with instance variables:
Let's say you have a class and an instance variable, you want that this instance variable takes only values of the type ATestClass and that conforms to ExampleProtocol
class GiveMeAGeneric<T: ATestClass where T: ExampleProtocol>
{
var aGenericVar : T?
}
Then instantiate it in this way:
var child = ATestClassChild()
let aGen = GiveMeAGeneric<ATestClassChild>()
aGen.aGenericVar = child
If child doesn't conform to the protocol ExampleProtocol, it won't compile
this method header from ObjC:
- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter { ... }
is identical to this header in Swift:
func addFilter<T: GPUImageOutput where T: GPUImageInput>(newFilter: T?) { ... }
both method will accept the same set of classes
which is based on GPUImageOutput class; and
conforms GPUImageInput protocol; and
the newFilter is optional, it can be nil;
From Swift 4 onwards you can do:
func addFilter(newFilter: GPUImageOutput & GPUImageInput)
Further reading:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html
http://braking.github.io/require-conformance-to-multiple-protocols/
Multiple Type Constraints in Swift