"Schwerwiegender Fehler: Array kann nicht von Objective-C überbrückt werden" - Warum versuchen Sie es überhaupt, Swift?

92

Ich habe ein Swift-Protokoll deklariert:

protocol Option {
    var name: String { get }
}

Ich erkläre mehrere Implementierungen dieses Protokolls - einige Klassen, einige Aufzählungen.

Ich habe einen Ansichts-Controller mit einer Eigenschaft, die wie folgt deklariert ist:

var options: [Option] = []

Wenn ich versuche, diese Eigenschaft auf ein Array von Objekten festzulegen, die das OptionProtokoll in anderen VCs implementieren prepareForSegue, wird ein Laufzeitfehler angezeigt:

fatal error: array cannot be bridged from Objective-C

Warum funktioniert das nicht? Der Compiler verfügt über alle erforderlichen Informationen, und ich verstehe überhaupt nicht, was Objective-C damit zu tun hat. Mein Projekt enthält nur Swift-Dateien, und diese Arrays kommen nicht in Framework-Methoden hinein oder aus diesen heraus erfordern, dass sie überbrückt werden NSArray.

Robert Atkins
quelle
6
Haben Sie versucht @objc, Ihrem Protokoll voranzukommen ? stackoverflow.com/a/28029568/377369
Fabio Poloni
1
Das funktioniert nicht, wenn eine der Protokollimplementierungen eine Aufzählung ist: "Nicht-Klassentyp 'Foo' kann nicht mit dem Klassenprotokoll 'Option' übereinstimmen"
Robert Atkins
Warum muss es aber ein Klassenprotokoll sein? Ich übergebe es nicht an ein Obj-C-Framework oder irgendetwas anderes, bei dem das Swift-Array mit NSArray verbunden werden muss.
Robert Atkins
Die Art und Weise, wie Swift und Objective-C zusammenarbeiten, ist für mich immer noch ein Geheimnis. Ich muss nur viele Dinge "akzeptieren", die nur "funktionieren" oder "nicht funktionieren".
Fabio Poloni
9
Warum hat dieser so viele Downvotes? Sieht für mich nach einer fairen und klaren Frage aus.
Guven

Antworten:

83

Ich habe eine Lösung gefunden. Es ist ziemlich ... unbefriedigend , aber es funktioniert. Wo ich das Array auf dem Zielansichts-Controller einstelle, mache ich:

destinationViewController.options = options.map({$0 as Option})
Robert Atkins
quelle
Kannst du nicht das ganze Array besetzen? options as [Option]
Kostiantyn Koval
Nee. Versuchte es (Xcode 6.3.1 (6D1002)), funktioniert nicht. Ich soll nicht braucht sie in jedem Fall zu gieße, der Compiler weiß , dass ich in einer Reihe von Dingen vorbei , die Option implementieren.
Robert Atkins
2
"Ein Array von Dingen, die Option implementieren" Ah, aber das ist nicht dasselbe wie ein Array von Optionen, was Sie brauchen. Siehe meine Antwort.
Matt
1
Das funktioniert und ja, es ist sehr unbefriedigend ... das sollte nicht nötig sein. Swift sollte in der Lage sein, damit umzugehen.
Oscar Gomez
Ich stimme zu ... es funktioniert so, aber es ist ein sehr unbefriedigendes Stück Code
Michael
22

Der Compiler weiß, dass ich ein Array von Dingen übergebe, die Option implementieren

Sie haben dort eine sehr aufschlussreiche Bemerkung hinterlassen, die die Ursache des Problems nahe legt. Ein "Array von Dingen, die Option implementieren" ist kein Array von Optionen.

Das Problem liegt in der Art des optionsRückens an dem Punkt, an dem Sie ihn erstellen (in prepareForSegue). Sie zeigen diesen Code nicht an, aber ich wette, dass Sie ihn zu diesem Zeitpunkt nicht umsetzen / eingeben können. Deshalb schlägt die Zuordnung fehl. optionsMöglicherweise gibt es eine Reihe von Dingen, die tatsächlich dazu führen, dass Option übernommen wird, aber das reicht nicht aus. Es muss als Array von Optionen eingegeben werden .

Also, zurück in prepareForSegue, bilden Sie Ihre optionswie folgt:

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

Jetzt können Sie es direkt zuweisen destinationViewController.options.

Hier ist ein kurzer Testfall (auf einem Spielplatz; ich verabscheue Spielplätze, aber sie können ihre Verwendung haben):

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

(Ich habe dies auch in einer tatsächlichen App mit einer tatsächlichen getestet prepareForSegue, und es funktioniert gut.)

matt
quelle
1
Ich denke , das im Extrem gebrochen wird , da der Compiler nicht zur Laufzeit weiß , dass Ding ist eine Option. Und auf jeden Fall funktioniert , wie im Kommentar zu meiner eigenen Antwort unten erwähnt, weder Casting ( viewController.options = things as [Option]) noch das Erstellen einer temporären Variablen, die explizit wie [Option]hier vorgeschlagen eingegeben wurde, tatsächlich. In beiden Fällen erhalte ich den Laufzeitfehler.
Robert Atkins
Dann musst du erklären, warum es bei mir funktioniert. Es ist noch etwas los, was Sie nicht angegeben haben. Wenn Sie keinen weiteren Code preisgeben, muss ich nur vermuten, dass Sie etwas Wesentliches zurückhalten.
Matt
Vielleicht. Aber ich bin immer noch verwirrt darüber, was dies überhaupt mit Objective-C zu tun hat (gegenüber dem ursprünglichen Laufzeitfehler). Ich mache nichts (was ich sehen kann), was eine Überbrückungsbesetzung erzwingen sollte NSArray.
Robert Atkins
2
Schau es dir so an. Ich habe dir Code gezeigt, der funktioniert. Sie haben nicht ich Code gezeigt, der nicht funktioniert Arbeit - ich kann das Problem aus den gegebenen Daten nicht reproduzieren. Hilf mir, es zu reproduzieren.
Matt
1
@ CristiBăluță Das ist, was Sie herausfinden müssten, bevor Sie behaupten "dieses Problem ist immer noch nicht behoben"
matt
16

Ich hatte das gleiche Problem und habe es behoben, indem ich mein Protokoll mit markiert habe @objc. In Ihrem Fall würde es so aussehen

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

Habe die Lösung aus dieser Antwort

Juan
quelle
1
Wie in den Kommentaren zur ursprünglichen Frage funktioniert dies nicht, wenn einer der Implementierer des Protokolls Swift Enums ist. Was sie in meinem Fall sind.
Robert Atkins
Tippfehler obcj sollte objc sein
Alan Scarpa
1

Dieser funktioniert auch gut

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