web-dev-qa-db-fra.com

Interface Builder, @IBOutlet et protocoles pour délégué et dataSource dans Swift

Impossible de connecter la propriété déléguée de CustomView déclarée comme @IBOutlet à ViewController dans Interface Builder - ne peut tout simplement pas établir de connexion.

Voici le code

class CustomView: UIView {
     @IBOutlet var delegate: CustomViewDelegate?
}

@objc protocol CustomViewDelegate {
     ...
}


class ViewController: UIViewController, CustomViewDelegate {
     ...
}

@objc est utilisé à cause de protocole Swift, la propriété IBOutlet ne peut pas avoir de type non objet , je ne sais pas pourquoi protocol CustomViewDelegate: class {} ne fonctionne pas.

Quelqu'un d'autre est tombé sur quelque chose comme ça?

28
Dmitry

D'après les notes de version de Xcode:

Interface Builder ne prend pas en charge la connexion à une prise dans un fichier Swift lorsque le type de la prise est un protocole.

Solution: déclarez le type de la prise en tant que AnyObject ou NSObject, connectez des objets à la prise à l'aide d'Interface Builder, puis modifiez le type de la prise en retour au protocole.

EDIT: Les notes de version de Xcode 9 beta 3 indiquent que cette solution de contournement ne devrait plus être nécessaire.

58
matt

Adam Waite fournit une solution de contournement intéressante. Je préfère cependant la solution suivante car elle met l'accent sur la solution de contournement et la propriété supplémentaire peut également être facilement supprimée une fois que Xcode est corrigé.

class CustomView: UIView {
    @IBOutlet
    public var delegate: CustomViewDelegate?

    /// Workaround for Xcode bug that prevents you from connecting the delegate in the storyboard.
    /// Remove this extra property once Xcode gets fixed.
    @IBOutlet
    public var ibDelegate: AnyObject? {
        get { return delegate }
        set { delegate = newValue as? CustomViewDelegate }
    }

    func someMethod() {
        // Here we always refer to `delegate`, not `ibDelegate`
        delegate?.onSomethingHappened()
    }
}

@objc protocol CustomViewDelegate {
    ...
}

Hé, ce bug a-t-il déjà un an et demi?

16
Lars Blumberg

Une solution de contournement élégante:

#if TARGET_INTERFACE_BUILDER
@IBOutlet open weak var delegate: AnyObject?
#else
open weak var delegate: CustomViewDelegate?
#endif

Voir : https://github.com/WenchaoD/FSPagerView/blob/master/Sources/FSPagerView.Swift#L88

9
WenchaoD

Un autre qui n'est pas joli mais:

@IBOutlet weak var ibDelegate: NSObject?
@IBOutlet weak var ibDataSource: NSObject?
var delegate: MultipleButtonViewDelegate? { return ibDelegate as? MultipleButtonViewDelegate }
var dataSource: MultipleButtonViewDataSource? { return ibDataSource as? MultipleButtonViewDataSource }
8
Adam Waite

C'est un vieux fil de discussion, mais je pensais souligner que depuis Xcode 9 beta 3, il est maintenant possible de connecter un délégué personnalisé écrit en Swift au constructeur d'interface.

Selon les notes de version

Interface Builder reconnaît désormais les sorties, les actions et les propriétés inspectables déclarées sur les classes qui ont une extension de protocole Swift. (22201035)

// Can connect this to interface builder now    
class MyViewController: UIViewController {
    @IBOutlet weak var myDelegate: TheNewDelegate?
}
3
DerrickHo328

Pour moi, la raison en était que la vue de table était nil au moment où j'ai essayé de définir sa source de données et son délégué. Cela était dû à l'initialiseur désigné appelant initWithNibName:bundle: qui ne garantit pas connexions initialisées . Le report de mon paramètre délégué et source de données sur viewDidload a fonctionné comme un charme.

1
Tom Howard