"Неустранимая ошибка: массив не может быть соединен с Objective-C" - Почему вы даже пытаетесь, Swift?

Я объявил протокол Swift:

protocol Option {
    var name: String { get }
}

Я объявляю несколько реализаций этого протокола - некоторые классы, некоторые перечисления.

У меня есть контроллер представления с объявленным как свойство:

var options: [Option] = []

Когда я пытаюсь установить это свойство в массив объектов, реализующих протокол Option в другом VC prepareForSegue, я получаю ошибку времени выполнения:

fatal error: array cannot be bridged from Objective-C

Почему это не работает? Компилятор имеет всю необходимую ему информацию, и я не понимаю, что с этим связано Objective-C - мой проект содержит только файлы Swift, и эти массивы не входят в какие-либо фреймворки, необходимо, чтобы их соединили до NSArray.

Ответ 1

Я нашел решение. Это довольно... неудовлетворительно, но это работает. Где я устанавливаю массив на контроллере представления назначения, я делаю:

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

Ответ 2

компилятор знает, что я передаю в Массив вещи, которые реализуют Option

Вы позволили сделать там очень показательное замечание, которое предлагает источник проблемы. "Массив объектов, реализующих опцию", не является массивом опций.

Проблема заключается в типе options назад в том месте, где вы его создали (в prepareForSegue). Вы не показываете этот код, но я держу пари, что вы не можете использовать/набирать его в этот момент. Вот почему неудача назначается. options может быть массивом вещей, которые на самом деле происходят с опцией Option, но этого недостаточно; его необходимо ввести в виде массива Option.

Итак, вернемся в prepareForSegue, сформируйте ваш options следующим образом:

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

Теперь вы сможете назначить его непосредственно destinationViewController.options.

Вот быстрый тестовый пример (на игровой площадке, я ненавижу игровые площадки, но они могут использовать их):

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

(Я также тестировал это в реальном приложении с фактическим prepareForSegue, и он отлично работает.)

Ответ 3

У меня была такая же проблема, и я исправил ее, отметив мой протокол @objc, в вашем случае это будет выглядеть как

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

Получено решение из этого ответа

Ответ 4

Этот тоже отлично работает

destinationViewController.options = options.map{$0}