web-dev-qa-db-fra.com

"erreur fatale: le tableau ne peut pas être ponté depuis Objective-C" - Pourquoi essayez-vous même, Swift?

J'ai déclaré un protocole Swift:

protocol Option {
    var name: String { get }
}

Je déclare plusieurs implémentations de ce protocole - certaines classes, certaines énumérations.

J'ai un contrôleur de vue avec une propriété déclarée comme suit:

var options: [Option] = []

Lorsque j'essaie de définir cette propriété sur un tableau d'objets qui implémentent le protocole Option dans le prepareForSegue d'un autre VC, j'obtiens une erreur d'exécution:

fatal error: array cannot be bridged from Objective-C

Pourquoi ça ne marche pas? Le compilateur a toutes les informations dont il a besoin, et je ne comprends pas du tout ce que Objective-C a à voir avec cela - mon projet ne contient que des fichiers Swift, et ces tableaux ne viennent pas dans ou hors des méthodes de framework qui nécessiteraient leur pontage vers NSArray.

92
Robert Atkins

J'ai trouvé une solution. C'est assez ... insatisfaisant, mais ça marche. Où je mets le tableau sur le contrôleur de vue de destination, je fais:

destinationViewController.options = options.map({$0 as Option})
83
Robert Atkins

le compilateur sait que je passe dans un tableau de choses qui implémentent Option

Vous avez laissé glisser une remarque très révélatrice, qui suggère la source du problème. Un "tableau de choses qui implémentent Option" n'est pas un tableau d'options.

Le problème vient du type de options à l'endroit où vous le créez (dans prepareForSegue). Vous ne montrez pas ce code, mais je parie que vous n'arrivez pas à le lancer/taper à ce stade. C'est pourquoi la mission échoue. options peut être un ensemble de choses qui, en fait, adoptent Option, mais ce n'est pas suffisant; il doit être tapé comme un tableau d'Option.

Donc, de retour dans prepareForSegue, formez votre options comme ceci:

let options : [Option] = // ... whatever ...

Maintenant vous pourrez l'affecter directement à destinationViewController.options.

Voici un cas de test rapide (dans une aire de jeux; je déteste les aires de jeux, mais ils peuvent avoir leurs utilisations):

protocol Option {
    var name : String {get}
}

class ViewController : UIViewController {
    var options : [Option] = []
}

enum Thing : Option {
    var name : String {
        get {
            return "hi"
        }
    }
    case Thing
}

let vc = ViewController()
let options : [Option] = [Thing.Thing]
vc.options = options // no problem

(J'ai également testé cela dans une application réelle avec un prepareForSegue réel, et cela fonctionne très bien.)

22
matt

J'avais le même problème et je l'ai corrigé en marquant mon protocole avec @objc, dans votre cas, cela ressemblerait à ceci

@objc protocol Option {
    var name: String { get }
}

Vous avez la solution de cette réponse

16
Juan

Celui-ci fonctionne également très bien

destinationViewController.options = options.map{$0}
1
Mykola Denysyuk