"Errore fatale: l'array non può essere colmato da Objective-C": perché ci stai provando, Swift?


92

Ho dichiarato un protocollo Swift:

protocol Option {
    var name: String { get }
}

Dichiaro più implementazioni di questo protocollo: alcune classi, alcune enumerazioni.

Ho un controller di visualizzazione con una proprietà dichiarata in questo modo:

var options: [Option] = []

Quando provo a impostare questa proprietà su un array di oggetti che implementano il Optionprotocollo in un altro VC prepareForSegue, ottengo un errore di runtime:

fatal error: array cannot be bridged from Objective-C

Perché non funziona? Il compilatore ha tutte le informazioni di cui ha bisogno e non capisco affatto cosa abbia a che fare Objective-C con esso: il mio progetto contiene solo file Swift e questi array non entrano o escono da nessun metodo di framework che potrebbe richiedono che siano collegati a NSArray.


6
Hai provato a anteporre @objcal tuo protocollo? stackoverflow.com/a/28029568/377369
Fabio Poloni

1
Ciò non funziona se una delle implementazioni del protocollo è un'enumerazione: "Il tipo non di classe 'Foo' non può essere conforme al protocollo di classe 'Opzione'"
Robert Atkins

Ma perché deve essere un protocollo di classe? Non lo sto passando a un framework Obj-C o qualsiasi altra cosa che richieda che Swift Array sia collegato a NSArray.
Robert Atkins

Il modo in cui Swift e Objective-C lavorano insieme è ancora un segreto per me. Devo solo "accettare" molte cose che semplicemente "funzionano" o "non funzionano".
Fabio Poloni

9
Perché questo ha così tanti voti negativi? Mi sembra una domanda chiara e giusta.
Guven

Risposte:


83

Ho trovato una soluzione. È abbastanza ... insoddisfacente , ma funziona. Dove ho impostato l'array sul controller della vista di destinazione, faccio:

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

non puoi lanciare l'intero array? options as [Option]
Kostiantyn Koval

No. Ho provato (Xcode 6.3.1 (6D1002)), non funziona. Non dovrei aver bisogno di lanciarlo in ogni caso, il compilatore sa che sto passando un array di cose che implementano l'opzione.
Robert Atkins,

2
"un array di cose che implementano l'opzione" Ah, ma non è la stessa cosa di un array di opzioni, che è ciò di cui hai bisogno. Vedi la mia risposta.
matt

1
Funziona, e sì, è molto insoddisfacente ... non dovrebbe essere necessario. Swift dovrebbe essere in grado di gestire i problemi.
Oscar Gomez

Sono d'accordo ... funziona in questo modo, ma è un codice molto insoddisfacente
Michael

22

il compilatore sa che sto passando un array di cose che implementano l'opzione

Ti sei lasciato sfuggire un'osservazione molto rivelatrice, che suggerisce l'origine del problema. Una "matrice di cose che implementano l'opzione" non è una matrice di opzioni.

Il problema è con il tipo di optionsschiena nel punto in cui lo crei (in prepareForSegue). Non mostri quel codice, ma scommetto che non lo lanci / digiti a quel punto. Ecco perché l'assegnazione fallisce. optionspuò essere una serie di cose che di fatto accadono per adottare Option, ma non è sufficiente; deve essere digitato come un array di Option.

Quindi, di nuovo dentro prepareForSegue, forma il tuo in optionsquesto modo:

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

Ora potrai assegnarlo direttamente a destinationViewController.options.

Ecco un breve test case (in un parco giochi; detesto i parchi giochi, ma possono avere i loro usi):

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

(L'ho testato anche in un'app reale con un'app reale prepareForSeguee funziona bene.)


1
Penso che questo è rotto in estrema perché il compilatore non sa in fase di esecuzione che cosa è un'opzione. E in ogni caso, come notato nel commento alla mia risposta di seguito, né casting ( viewController.options = things as [Option]) né la creazione di una variabile temporanea digitata esplicitamente [Option]come suggerisci qui, funziona effettivamente. In entrambi i casi ottengo l'errore di runtime.
Robert Atkins

Quindi devi spiegare perché funziona per me. Sta succedendo qualcos'altro che non hai dichiarato. Se non riveli altro codice, devo semplicemente sospettare che stai trattenendo qualcosa di essenziale.
matt

Può essere. Ma sono ancora confuso su cosa abbia a che fare con Objective-C in primo luogo (rispetto all'errore di runtime originale.) Non sto facendo nulla (che posso vedere) che dovrebbe forzare un cast di bridging a NSArray.
Robert Atkins

2
Guardate in questo modo. Ti ho mostrato un codice che funziona. Non mi hai mostrato il codice che non funziona - non posso riprodurre il tuo problema dai dati forniti. Aiutami a riprodurlo.
matt

1
@ CristiBăluță Questo è ciò che dovresti scoprire prima di affermare che "questo problema non è ancora stato risolto"
matt

16

Avevo lo stesso problema e l'ho risolto contrassegnando il mio protocollo con @objc, nel tuo caso sarebbe simile a questo

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

Ho ottenuto la soluzione da questa risposta


1
Come nei commenti alla domanda originale, questo non funziona se qualcuno degli implementatori del protocollo è Swift Enums. Che nel mio caso lo sono.
Robert Atkins

errore di battitura obcj dovrebbe essere objc
Alan Scarpa

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.