“Фатальна помилка: масив неможливо зв’язати з Objective-C” - Чому ти взагалі намагаєшся, Свіфте?


92

Я оголосив протокол Swift:

protocol Option {
    var name: String { get }
}

Я заявляю про декілька реалізацій цього протоколу - деякі класи, деякі перелічення.

У мене є контролер перегляду з властивістю, оголошеною так:

var options: [Option] = []

Коли я намагаюся встановити для цього властивості масив об'єктів, що реалізують Optionпротокол в інших ВК prepareForSegue, я отримую помилку виконання:

fatal error: array cannot be bridged from Objective-C

Чому це не працює? Компілятор має всю необхідну інформацію, і я не розумію, що взагалі з цим має відношення Objective-C - мій проект містить лише файли Swift, і ці масиви не надходять і не виходять з будь-яких методів фреймворку, які вимагати від них мосту NSArray.


6
Ви намагалися додати @objcсвій протокол? stackoverflow.com/a/28029568/377369
Фабіо Poloni

1
Це не працює, якщо будь-яка реалізація протоколу є переліком: "Некласовий тип 'Foo' не може відповідати протоколу класу 'Option'"
Роберт Аткінс,

Чому це повинен бути протокол класу? Я не передаю його в фреймворк Obj-C або щось інше, що вимагає переведення мосту Swift Array у NSArray.
Роберт Аткінс,

Вони сподіваються, що Свіфт та Objective-C працюють разом, для мене досі секрет. Я просто повинен "прийняти" багато речей, які просто "працюють" або "не працюють".
Фабіо Полоні

9
Чому у нього так багато голосів проти? Мені здається справедливим і зрозумілим питанням.
venувен

Відповіді:


83

Я знайшов рішення. Це цілком ... незадовільно , але це працює. Де я встановлюю масив на контролері перегляду призначення, який я роблю:

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

ви не можете кинути цілий масив? options as [Option]
Костянтин Коваль

Ні. Спробував (Xcode 6.3.1 (6D1002)), не працює. Мені не потрібно кидати його в будь-якому випадку, компілятор знає, що я передаю масив речей, які реалізують Option.
Роберт Аткінс,

2
"масив речей, що реалізують Option" Ах, але це не те саме, що масив Option, що саме вам потрібно. Дивіться мою відповідь.
matt

1
Це працює, і так, це дуже незадовільно ... це не потрібно. Свіфт повинен мати можливість обробляти htis.
Оскар Гомес,

Я згоден ... це працює таким чином, але це дуже незадовільний біт коду
Майкл

22

компілятор знає, що я передаю масив речей, що реалізують Option

Ви пропустили там дуже показове зауваження, яке наводить на думку джерело проблеми. "Масив речей, що реалізують Option", не є масивом 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, і він працює чудово.)


1
Я думаю , що це зіпсовано в крайності , тому що компілятор дійсно знає , що під час виконання Thing є варіантом. І в будь-якому випадку, як зазначено у коментарі до моєї власної відповіді нижче, ані casting ( viewController.options = things as [Option]), ані створення тимчасової змінної, явно набраної, [Option]як ви пропонуєте тут, насправді не працює. В обох випадках я отримую помилку виконання.
Роберт Аткінс,

Тоді ти повинен пояснити, чому це працює у мене. Щось інше відбувається, про що ви не заявили. Якщо ви не розкриєте більше коду, я просто повинен підозрювати, що ви стримуєте щось важливе.
matt

Може бути. Але я все ще бентежусь щодо того, яке це взагалі має відношення до Objective-C (відносно початкової помилки виконання). Я не роблю нічого (що я бачу), що повинно змусити мостовий привід NSArray.
Роберт Аткінс

2
Подивіться на це так. Я показав вам код, який працює. Ти маєш не показали мені код, який не працює - я не можу відтворити вашу проблему на основі даних. Допоможіть мені його відтворити.
matt

1
@ CristiBăluță Це те, що вам потрібно було б з’ясувати, перш ніж стверджувати, що "ця проблема все ще не вирішена"
мат,

16

У мене була та сама проблема, і я виправив її, позначивши мій протокол @objc, у вашому випадку це буде виглядати так

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

Отримав рішення з цієї відповіді


1
Як і в коментарях до вихідного питання, це не працює, якщо хтось із реалізаторів протоколу є Swift Enums. Які в моєму випадку вони є.
Роберт Аткінс,

друкарська помилка obcj повинна бути objc
Алан Скарпа

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.