14

I have created a class "DeletableImageView" (.swift + .xib) which uses the protocol I defined as "DeletableImageViewDelegate" through a property I called delegate.

Example for sake of clarity:

DeletableImageView.swift

protocol DeletableImageViewDelegate {
    func deleteImageWithTag(tag: Int!) -> (Bool)
    func addImageOnViewWithTag(tag: Int!) -> (Bool)
    ...
}

class DeletableImageView: UIView {

    var view: UIView!
    var delegate: DeletableImageViewDelegate?

    // Some random methods + some use of the delegate protocol's methods
    ...
}

My problem is that now, when I try to use my class in a controller from the associated .xib file (which means that I drag and drop a view in interface builder and assign the DeletableImageView class to this view) I cannot link the delegate property (even if I declare this property as an IBOutlet).

What I want to be able to do is to directly link the view's delegate outlet to the "File's Owner" in the .xib

The exact same thing you do when you link datasource and delegate from a tableview directly in the .xib file.

But when I control-drag they won't link together.

Does anyone have any idea of what is happening ?

Thank you very much.

Matthieu luci
  • 141
  • 1
  • 4
  • Does the file owner conform to the protocol? – luk2302 Nov 19 '15 at 17:26
  • Yes the file owner conforms to the protocol ... – Matthieu luci Nov 19 '15 at 18:09
  • Here is a video I made to help you understand my problem : https://youtu.be/clYFj6dkaWk – Matthieu luci Nov 19 '15 at 18:30
  • 1
    looks like a bug to me - can reproduce the issue. I can connect to classes, but not protocols. – luk2302 Nov 19 '15 at 19:04
  • 1
    a pretty old bug http://stackoverflow.com/questions/24561490/swift-protocol-iboutlet-property-cannot-have-non-object-type and https://forums.developer.apple.com/thread/13465 AAAAND http://stackoverflow.com/questions/26180268/interface-builder-iboutlet-and-protocols-for-delegate-and-datasource-in-swift :/ – luk2302 Nov 19 '15 at 19:09
  • Thanks @luk2302 !! You're right, it is a bug ! When I change the delegate property type to AnyObject it works ! :D – Matthieu luci Nov 19 '15 at 19:28

2 Answers2

5

First thing you need to do is to add @objc in from of your protocol definition, so that it looks like:

@objc protocol DeletableImageViewDelegate {
    ...
}

You might ask why do you need to do this. It's because you want to add delegate property to the storyboard, and in order to set some property visible by storyboard, it must have @IBOutlet prefix, and that prefix requires it to be Objective C protocol.

So the next thing you want to do is change var delegate: DeletableImageViewDelegate? to

@IBOutlet var delegate: DeletableImageViewDelegate?

Now if you right click on the view in the interface builder you will get something like this, which means that we exposed our delegate property to the interface builder. Exposed property

If you try to connect it to file owner (for example UIViewController), it will not work because your file owner still doesn't implement that protocol. To implement it you need to write:

extension UIViewController : DeletableImageViewDelegate {
    // Implementation
}

After you do that, you should be able to connect delegate property to the view controller, thus receiving delegate method messages. In each case your file owner must implement the protocol.

Said Sikira
  • 4,482
  • 29
  • 42
  • I tried it but it's still not working, I'm starting to wonder if this might be a bug of XCode cause the new version has a lot of problem with my .xib(s) or maybe it's juste on my mac ... It's still not possible to link the view to the file ower ... I would like to precise that I ** DON'T USE STORYBOARDS !!!**, maybe this is why it is not working ? – Matthieu luci Nov 19 '15 at 18:11
  • Here is a video I made to help you understand my problem : https://youtu.be/clYFj6dkaWk – Matthieu luci Nov 19 '15 at 18:30
  • Now I see that your deletable view is a subview of the main view in the xib. Add extension to the `UIView` and you should be good. – Said Sikira Nov 19 '15 at 19:21
  • 5
    It was a bug, @luk2302 was right, I changed the delegate property to type to "AnyObject" and now it works ! :) Anyway, thank you both of you ! – Matthieu luci Nov 19 '15 at 19:31
0

I've created solution similar as in the comments. But I've also wanted not have to cast delegate every time and check for protocol implementation.

weak var delegate: MenuViewDelegate?
@IBOutlet weak var _delegate: AnyObject? {
    didSet {
        if let d = _delegate {
            if let d = (d as? MenuViewDelegate) {
                delegate = d
            } else {
                print("ERROR: delegate does not implement \(d) MenuViewDelegate protocol")

                d as! MenuViewDelegate
            }
        }
    }
}
Dracris
  • 93
  • 9