How to add protocol type as subview

641 Views Asked by At

So I wrote a simple protocol:

protocol PopupMessageType{
    var cancelButton: UIButton {get set}
    func cancel()
}

and have a customView:

class XYZMessageView: UIView, PopupMessageType {
...
}

and then I currently have:

class PopUpViewController: UIViewController {

    //code...

    var messageView : CCPopupMessageView!
    private func setupUI(){
    view.addSubview(messageView)

    }

}

But what I want to do is:

class PopUpViewController: UIViewController {

    //code...

    var messageView : PopupMessageType!
    private func setupUI(){
    view.addSubview(messageView) // ERROR

    }

}

ERROR I get:

Cannot convert value of type 'PopupMessageType!' to expected argument type 'UIView'

EDIT: I'm on Swift 2.3!

3

There are 3 best solutions below

3
On BEST ANSWER

Change the type of property messageView to (UIView & PopupMessageType)!

I mean

class PopUpViewController: UIViewController {

    //code...

    var messageView : (UIView & PopupMessageType)!
    private func setupUI(){
    view.addSubview(messageView) // ERROR

    }

}
6
On

In Swift 4 you can do this:

typealias PopupMessageViewType = UIView & PopupMessageType

And then use PopupMessageViewType as the type of the variable.

2
On

DISCLAIMER: I do not have the swift 2.3 compiler anymore since swift 4 is the new normal for iOS development. The following code may possibly need tweaks to get it working in swift 2.3


Essentially we will be making a 2x1 mux where the two inputs are the same object. The output depends on whether you set the mux to choose the first or the second one.

// The given protocol
protocol PopupMessageType{
    var cancelButton: UIButton {get set}
    func cancel()
}

// The object that conforms to that protocol
class XYZMessageView: UIView, PopupMessageType {
    var cancelButton: UIButton = UIButton()
    func cancel() {
    }
}

// The mux that lets you choose the UIView subclass or the PopupMessageType
struct ObjectPopupMessageTypeProtocolMux<VIEW_TYPE: UIView> {
    let view: VIEW_TYPE
    let popupMessage: PopupMessageType
}

// A class that holds and instance to the ObjectPopupMessageTypeProtocolMux
class PopUpViewController: UIViewController {
    var messageWrapper : ObjectPopupMessageTypeProtocolMux<UIView>!
    private func setupUI(){
        view.addSubview(messageWrapper.view)
    }
}

//...
let vc = PopUpViewController() // create the view controller
let inputView = XYZMessageView() // create desired view

// create the ObjectPopupMessageTypeProtocolMux
vc.messageWrapper = ObjectPopupMessageTypeProtocolMux(view: inputView, popupMessage: inputView) //<-- 1

vc.messageWrapper.view // retreive the view
vc.messageWrapper.popupMessage.cancel() // access the protocol's methods
vc.messageWrapper.popupMessage.cancelButton // get the button

1) I input the "inputView" twice for the initializer of ObjectPopupMessageTypeProtocolMux. They are the same class instance, but they get casted to different types.

I hope this helps you get to where you wanna go in swift 2.3