Validate conformance object to protocol with associated type - swift

This is my code:
protocol Protocol {
associatedtype A
}
class Class: Protocol {
typealias A = Int
}
assert(type(of: Class()) == Protocol.self)
The error is ofcourse:
Protocol 'Protocol' can only be used as a generic constraint because
it has Self or associated type requirements
I understand the error, but I hope there is some way to check if a given object conform to a protocol with an associated type, without the need of binding/casting.

Related

Class conforming protocol throws "cannot conform to" class error

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.
}
}

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 4 - Subclass Generic Constraint from associatedtype

I'd like to write a Swift protocol that requires a type to specify a base class and implement methods that operate on subclasses of that base class. Here's what that might look like (doesn't compile):
protocol Repository {
associatedtype BaseModel
//T must subclass BaseModel
func all<T: BaseModel>(from type: T.Type) -> [T]
}
But this generates the following compiler error:
Inheritance from non-protocol, non-class type 'Self.BaseModel'
This makes sense, because BaseModel could be specified with a struct type and subclassing wouldn't be allowed. So I tried creating an empty protocol, constrained to classes, to try to inform the compiler that this type will be a class type and allow a subclass constraint.
protocol Model: class { }
Then I constrained the BaseModel type using the Model class protocol:
associatedtype BaseModel: Model
But this generates the same compiler error from above. Is it possible to enforce a subclass constraint from an associatedtype on a protocol? I would expect the above to compile or for Swift to allow something like the following to allow subclass constraints:
associatedtype BaseModel: class
Associated Types should be used when type is unknown before the protocol is implemented. But if type is known no need to use associated type. I guess you could do this.
protocol Model: class { }
class BaseModel : Model { }
protocol Repository {
func all<T : BaseModel>(from type: T.Type) -> [T]
}

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 {
// ...
}

Specify associated type of parent protocol in child protocol with Swift

In Swift 2, I have a protocol:
protocol Protocol {
typealias Type
}
When I want to use Protocol without defining what type to use for Type:
var protocol1: Protocol
Then I'm getting the following error:
Protocol 'Protocol' can only be used as a generic constraint because it has Self or associated type requirements
It is clear why this is not going to work.
I have another protocol, which inherits from the first protocol and specifies that the associated type Type should be a String.
protocol AnotherProtocol: Protocol {
typealias Type = String
}
The same error occurs, when I try to use this protocol:
var protocol2: AnotherProtocol
Protocol 'AnotherProtocol' can only be used as a generic constraint because it has Self or associated type requirements
Why am I getting an error for this, although I have specified the associated type?
Is there another way for the second protocol to specify the associated type of the parent protocol, without having to specify it again in every class that implements the second protocol?
Your error isn't coming from the declaration or definition of your protocols, it comes from how you're trying to use them. There are two basic ways you can use a protocol: as a pseudo-type, or as a constraint. When you declare a variable like this:
var protocol1: Protocol
You're using the protocol like it's a type: the type of protocol1 is Protocol. This is different from using it as a constraint. Other types conform to the protocol if it's used as a constraint:
struct SomeStruct: Protocol {...
Now, you can use your protocols in either way, but there are some disadvantages to both ways. Firstly, you can't store a heterogenous collection of "protocols as a constraint", whereas you can when you use protocols as a type.
Secondly, if there are requirements on self or associated types, you can no longer use that protocol as a type.
So, here's what I think you're looking for. Your first protocol:
protocol Protocol {
typealias Type
}
And then the second:
protocol InheritingProtocol {
typealias Type = String
}
Now, if you want something to conform to the second protocol, it must be used as a constraint. That means that some type conforms to the protocol, and then you can have some instance of that type.
struct SomeType : InheritingProtocol {}
let someInstance = SomeType()