Can a protocol require conforming types to be a subtype of another type? - swift

For example: I'd like to say in a protocol definition that, a class conforming it, needs to also subclass UIView or another custom class type MyClass. Is that possible?

Yes you can, just define your protocol as:
protocol SomeProtocol where Self: MyClass {
// protocol code here
}

Related

Protocol inheritance from class?

I read the documentation about Protocols and can't find any information about protocol inheriting from a class, but the code compiles. As far as I remember protocols can only inherit other protocols, I have never seen protocol that inherits from a class. I don't even know a language that allows such behaviour.
class A {
}
protocol X: A {
}
// forced to inherit from class A, because of X protocol
class B: A, X {
}
Is it some kind of bug?
Implemented In Swift 5: From the Swift 5 Release notes
Protocols can now constrain their conforming types to those that subclass a given class. Two equivalent forms are supported:
protocol MyView: UIView { /*...*/ }
protocol MyView where Self: UIView { /*...*/ }
See this tweet by John Sundell, showing a possible use case

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

How do I specify a typealias of a scene conforming to a specific protocol?

I want to define a type which refers to only objects which are:
Members of a subclass of a given class
Conform to a specific protocol
How can I specify such a type? For instance, I'd like to be able to do something like this:
//Define a class
class MyClass {}
//Define a protocol
protocol MyProtocol {}
//Define an extension specific to this class and protocol
extension MyProtocol where Self : MyClass {}
//This works for multiple protocols, but not a class and a protocol
typealias MyAlias = MyClass & MyProtocol

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

Declare class variable as conforming to Swift protocol

In Swift, how would I declare a variable that explicitly states that it conforms to some protocol? The objective-c equivalent would be #property id<NSObject>
From my understanding, doing this:
var a: NSObject
declares a variable that is of type NSObject protocol but I don't to do that, I want to declare a variable of type AnyObject that conforms. I'm also interested in finding out how to declare an array of objects in which each object conforms to that protocol.
There is really no need for AnyObject here; if all you care about is conformance to a protocol Proto, you can simply write var a: Proto. (In some cases your protocol may use Self or other things that require it to be used as a generic constraint; you would then use class C<T: Proto> { var a: T }.
The NSObject protocol is imported into Swift as NSObjectProtocol (due to a name conflict with the NSObject class), therefore, it would be
var a: NSObjectProtocol
In Swift 4 it's possible an easier way. You can declare variable of some class conforming to protocol at the same time. You can do it like this:
var someVar: ClassA & ProtocolA & ProtocolB