Declare class variable as conforming to Swift protocol - swift

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

Related

Error "Redundant constraint 'Self' : 'AnyObject'" - where is the `AnyObject`?

I found a strange Swift compiler message while developing (I'm using Swift 4.1):
protocol Foo: class where Self: NSObject { // (1)
// Redundant constraint 'Self' : 'AnyObject'
}
What is happening here?
First, this is not redundant. When I write
protocol Foo: class { } // (2)
I have a protocol that any object could potentially conform to, even objects that don't derive from NSObject. But I can create weak references: weak var f: Foo? is okay.
On the other hand, when I write
protocol Foo where Self: NSObject { } // (3)
I have a protocol where I cannot produce weak references: weak var f: Foo? is a compile time error.
Second, where does the AnyObject come from? I'm asking for NSObject. The NSObject is respected though: I cannot declare a class MyFoo: Foo { } because it rightly complains that it must inherit from NSObject?
Is this a bug in Swift? Or am I missing something? If it is a bug: is it a bug because snippet (3) does not let me take weak references? Or because of the compiler warning? Or both? And if I am missing something: what is it?
It is not possible to constrain a protocol to be subclasses of a specific class in Swift 4.1. You can inherit Foo from NSObjectProtocol, which probably matches your intent.
protocol Foo: NSObjectProtocol {
// ....
}
In Swift 4.2, what you've written is legal Swift and does what you expect.
From the Swift public API:
public typealias AnyObject
/// The protocol to which all class types implicitly conform.
So by declaring your protocol to conform to class it automatically conforms to AnyObject

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

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
}

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

Swift protocol as generic type

I have this kind of code:
protocol MyProtocol {
}
class P1: MyProtocol {
}
class P2: MyProtocol {
}
class C <T: MyProtocol> {
}
Then i need to define a variable to delegate all kinds of C<MyProtocol>:
var obj: C <MyProtocol>
But compile error comes:
Using 'MyProtocol' as a concrete type conforming to protocol 'MyProtocol' is not supported
How can I do?
This code:
class C <T: MyProtocol> { }
Means that C is a generic class that can specialize on any type T that conforms to MyProtocol.
When you declare:
var obj: C <MyProtocol>
You are (I think) trying to say that the var obj will be an instance of C specialized to some type that conforms to MyProtocol,but you can't specialize a generic class on a protocol type, because there is no such thing as a direct concrete instance of a protocol. There can only be instances of a type conforming to the protocol. And there can theoretically be many different types that conform to the protocol. So that notation doesn't really tell the compiler which specific specialization of C to use.
This shouldn't be a problem though, because you can write things like:
var obj: C<P1> = C<P1>()
or
var obj = C<P2>() // type is inferred
And within your class C you can still treat any uses of T as conforming to MyProtocol. So I think this should give you everything you need, as long as you remember that an instance of a generic class must be specialized to a single specific concrete type, not a protocol which could represent many possible concrete types.
You usually don't need to declare type for a Swift's variable. The compiler can infer type in most cases. Also, for generic class, you should let the compiler figure out what the generic classes resolve to:
class C<T: MyProtocol> {
var value: T
init (value: T) {
self.value = value
}
}
var obj = C(value: P1()) // type: C<P1>
// or:
var obj = C(value: P2()) // type: C<P2>

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()