“Fatal error: array tidak bisa dijembatani dari Objective-C” —Kenapa kau mencoba, Swift?

92

Saya telah menyatakan protokol Swift:

protocol Option {
    var name: String { get }
}

Saya mendeklarasikan beberapa implementasi protokol ini — beberapa kelas, beberapa enum.

Saya memiliki pengontrol tampilan dengan properti yang dideklarasikan sebagai:

var options: [Option] = []

Ketika saya mencoba dan mengatur properti ini ke array objek yang mengimplementasikan Optionprotokol di VC lain prepareForSegue, saya mendapatkan error runtime:

fatal error: array cannot be bridged from Objective-C

Mengapa ini tidak berhasil? Kompiler memiliki semua informasi yang dibutuhkannya, dan saya sama sekali tidak mengerti apa hubungannya Objective-C dengannya — proyek saya hanya berisi file Swift, dan array ini tidak masuk atau keluar dari metode kerangka kerja yang akan mengharuskan mereka dijembatani NSArray.

Robert Atkins
sumber
6
Apakah Anda mencoba menambahkan @objcprotokol Anda? stackoverflow.com/a/28029568/377369
Fabio Poloni
1
Itu tidak berfungsi jika salah satu implementasi protokol adalah enum: "Jenis non-kelas 'Foo' tidak dapat mengikuti protokol kelas 'Opsi'"
Robert Atkins
Mengapa harus menjadi protokol kelas? Saya tidak meneruskannya ke framework Obj-C atau apa pun yang memerlukan Swift Array untuk dihubungkan ke NSArray.
Robert Atkins
Cara Swift dan Objective-C bekerja sama masih menjadi rahasia bagi saya. Saya hanya harus "menerima" banyak hal yang hanya "berhasil" atau "tidak berhasil".
Fabio Poloni
9
Mengapa yang satu ini memiliki begitu banyak suara negatif? Sepertinya pertanyaan yang adil dan jelas bagi saya.
Guven

Jawaban:

83

Saya telah menemukan solusi. Ini cukup ... tidak memuaskan , tapi berhasil. Di mana saya mengatur array pada pengontrol tampilan tujuan yang saya lakukan:

destinationViewController.options = options.map({$0 as Option})
Robert Atkins
sumber
tidak bisakah kamu melakukan cast seluruh array? options as [Option]
Kostiantyn Koval
Nggak. Sudah mencobanya (Xcode 6.3.1 (6D1002)), tidak berfungsi. Saya tidak perlu mentransmisikannya dalam hal apa pun, kompilator tahu bahwa saya meneruskan Array hal-hal yang mengimplementasikan Option.
Robert Atkins
2
"Array of things that implement Option" Ah, tapi itu tidak sama dengan Array of Option, yang Anda butuhkan. Lihat jawabanku.
matt
1
Ini berfungsi, dan ya itu sangat tidak memuaskan ... ini seharusnya tidak diperlukan. Swift harus bisa menangani htis.
Oscar Gomez
Saya setuju ... cara kerjanya seperti ini, tetapi ini adalah kode yang sangat tidak memuaskan
Michael
22

kompilator tahu bahwa saya meneruskan Array hal-hal yang mengimplementasikan Option

Anda telah memberikan komentar yang sangat terbuka, yang menunjukkan sumber masalah. Sebuah "Array of things yang mengimplementasikan Option" bukanlah Array of Option.

Masalahnya adalah dengan jenis optionspunggung pada titik tempat Anda membuatnya (dalam prepareForSegue). Anda tidak menunjukkan kode itu, tetapi saya bertaruh bahwa Anda gagal memasukkan / mengetiknya pada saat itu. Itulah mengapa penugasan gagal. optionsmungkin serangkaian hal yang sebenarnya terjadi karena mengadopsi Opsi, tetapi itu tidak cukup; itu harus diketik sebagai larik Opsi.

Jadi, kembali ke dalam prepareForSeguebentuk optionsseperti ini:

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

Sekarang Anda dapat menetapkannya langsung ke destinationViewController.options.

Berikut adalah kasus uji singkat (di taman bermain; Saya tidak suka taman bermain, tetapi mereka dapat menggunakannya):

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

(Saya juga menguji ini di aplikasi aktual dengan yang sebenarnya prepareForSegue, dan berfungsi dengan baik.)

Matt
sumber
1
Saya pikir ini rusak dalam ekstrem karena compiler tidak tahu pada runtime yang Masalahnya Opsi. Dan bagaimanapun, seperti yang dicatat dalam komentar untuk jawaban saya sendiri di bawah ini, baik casting ( viewController.options = things as [Option]) atau membuat variabel temp yang diketik secara eksplisit [Option]seperti yang Anda sarankan di sini, sebenarnya berfungsi. Dalam kedua kasus saya mendapatkan error runtime.
Robert Atkins
Kemudian Anda harus menjelaskan mengapa itu berhasil untuk saya. Ada hal lain yang terjadi yang belum Anda nyatakan. Jika Anda tidak mengungkapkan lebih banyak kode, saya hanya perlu curiga bahwa Anda menahan sesuatu yang penting.
matt
Mungkin. Tapi saya masih bingung apa hubungannya ini dengan Objective-C di tempat pertama (vis. Kesalahan runtime asli.) Saya tidak melakukan apa pun (yang bisa saya lihat) yang seharusnya memaksa pemain penghubung NSArray.
Robert Atkins
2
Lihat seperti ini. Saya telah menunjukkan kepada Anda kode yang berfungsi. Anda belum menunjukkan kepada saya kode yang tidak berfungsi - Saya tidak dapat mereproduksi masalah Anda dari data yang diberikan. Bantu saya mereproduksinya.
matt
1
@ CristiBăluță Itulah yang perlu Anda ketahui sebelum mengklaim "masalah ini masih belum diperbaiki"
matt
16

Saya mengalami masalah yang sama dan memperbaikinya dengan menandai protokol saya @objc, dalam kasus Anda akan terlihat seperti ini

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

Dapatkan solusi dari jawaban ini

Juan
sumber
1
Seperti pada komentar di pertanyaan awal, ini tidak berfungsi jika salah satu pelaksana protokol adalah Swift Enums. Yang mana dalam kasus saya mereka.
Robert Atkins
typo obcj harus menjadi objc
Alan Scarpa
1

Yang ini juga berfungsi dengan baik

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