31

In Objective-C, it's possible to write something like that:

@property(retain) UIView<Protocol1, Protocol2, ...> *myView;

But how can I write this code in swift?

I already know how to make a property conform to many protocols, but it does not work by using the inheritance:

var myView: ??? protocol<Protocol1, Protocol2, ...>

Edit:

I use many UIView subtypes like UIImageView, UILabel or others, and I need to use some of the UIView properties plus some methods defined in the protocols. In the worst case I could create a UIViewProtocol with the needed properties, but I would know if it is possible in Swift to declare a property/variable with a type and some protocol to conform with.

Binarian
  • 12,296
  • 8
  • 53
  • 84
Yannick Loriot
  • 7,107
  • 2
  • 33
  • 56
  • 1
    I don't think it's possible like you could in Objective-C. Could you possibly tell a bit more about the protocols? Think there might be a different approach which will be more suitable for Swift. – Guido Hendriks Sep 10 '14 at 14:52
  • I don't understand why you would try to coerce a class like UIView or UILabel to conform to some protocol that it isn't already conforming to, in which case, there's no need to specify it. Are you extending these classes to conform to new protocols? – Tom Erik Støwer Sep 10 '14 at 17:09
  • @TomErikStøwer I think this is the best solution indeed. I'm still learning Swift and I would know if it was possible like in Objective-C. Yes I extend them to conform to the new protocols so there is no prob. – Yannick Loriot Sep 10 '14 at 18:44
  • @GuidoHendriks the protocols are juste there to help me for some view selections and drag&drop stuff. Like I said previously I'm still learning Swift so I try new things to learn by the same way. – Yannick Loriot Sep 10 '14 at 18:47
  • 1
    @YannickL. Ok I see, but if you are already extending those classes, wouldn't then the protocol conformance be implicit from the point of view of the property declaration? – Tom Erik Støwer Sep 10 '14 at 19:28
  • duplicate of http://stackoverflow.com/questions/26401778/swift-how-can-i-declare-a-variable-of-a-specific-type-that-conforms-to-one-or-m – Daniel Galasko Sep 07 '15 at 15:16

3 Answers3

26

You can do this with a generic class using a where clause:

A where clause enables you to require that an associated type conforms to a certain protocol, and/or that certain type parameters and associated types be the same.

To use it, make the class your property is defined in a generic class with a type constraint to check if the type parameter for your property matches your desired base class and protocols.

For your specific example, it could look something like this:

class MyViewController<T where T: UIView, T: Protocol1, T: Protocol2>: UIViewController {
    var myView: T

    // ...
}
Mike S
  • 41,895
  • 11
  • 89
  • 84
  • 1
    Great answer. Do you know how this is different from `class MyViewController: UIViewController { }` ? – Kamchatka Sep 15 '14 at 09:20
  • I'm pretty sure that's exactly the same. I guess I just got caught up in using `where` and didn't try the more concise format. – Mike S Sep 15 '14 at 14:38
  • 6
    In order to use this solution, you'd have to specify the T if you initialize the controller. It's no problem if there is a single object in the property, but in my case I have an array which can contain multiple objects instantiated from different subclasses of the base class. @MikeS How would you approach this problem? – Lukáš Kubánek Jan 19 '15 at 13:26
  • @LukasKubanek if I understand what you're asking, you can just define the property as an array of `T`s: `var myProperty: Array` or `var myProperty: [T]` – Mike S Jan 19 '15 at 21:40
  • But in that case you'd have to specify the concrete type when instantiating the container object. See https://gist.github.com/lukaskubanek/ed82cf679c36b5a0b0a1 – Lukáš Kubánek Jan 19 '15 at 22:14
  • @LukasKubanek Ah, I see... I can't think of a way to do that offhand. Like you said, you'd have to pass the concrete type when instantiating the container, so you'd either have to pass `FirstConformClass` or `SecondConformClass` (from your gist) and then you'd just have a container of one of those types, not both. – Mike S Jan 20 '15 at 16:58
6

In Swift 4 it's finally possible. You can declare variable of some class conforming to protocol at the same time, like this:

class ClassA {
    var someVar: String?
}

protocol ProtocolA {}

class ClassB {
    var someOptional: (ClassA & ProtocolA)? // here is optional value
    var some: ClassA & ProtocolA // here is non-optional value; need to provide init though :)
}
Vladyslav Zavalykhatko
  • 15,202
  • 8
  • 65
  • 100
5

One and probably a bit ugly one of the ways to do that, is to create a wrapper protocol for UIView:

protocol UIViewRef {
    var instance: UIView { get }
}

Now it is possible to create a protocol which implements Protocol1, Protocol2 and UIViewRef, which is going to be used to get the UIView itself:

protocol MyUIViewProtocol: UIViewRef, Protocol1, Protocol2 { }

And last step will be implementing UIViewRef protocols for your UIViews, which, in you case, as I understand, already implement Protocol1 and Protocol2:

// SomeOfMyViews already implements Protocol1 and Protocol2
extension SomeOfMyUIViews: MyUIViewProtocol {
    var instance: UIView { return self }
}

As the result we have MyUIViewProtocol, implementers of which hold a reference to a UIView and each of them implement Protocol1 and Protocol2. One caveat though - to get the UIView itself, we need to ask it's reference from instance property. For example

// Lets say we're somewhere in a UIViewController
var views: [SomeOfMyUIView] = // Get list of my views
views.forEach { self.view.addSubview($0.instance) }
Andrew Slabko
  • 690
  • 8
  • 15