„Błąd krytyczny: nie można mostkować tablicy z Objective-C” - Dlaczego w ogóle próbujesz, Swift?

92

Deklarowałem protokół Swift:

protocol Option {
    var name: String { get }
}

Deklaruję wiele implementacji tego protokołu - niektóre klasy, niektóre wyliczenia.

Mam kontroler widoku z właściwością zadeklarowaną jako tak:

var options: [Option] = []

Kiedy próbuję ustawić tę właściwość na tablicę obiektów, które implementują Optionprotokół w innym VC prepareForSegue, pojawia się błąd wykonania:

fatal error: array cannot be bridged from Objective-C

Dlaczego to nie działa? Kompilator ma wszystkie potrzebne informacje i w ogóle nie rozumiem, co ma z tym wspólnego Objective-C - mój projekt zawiera tylko pliki Swift, a te tablice nie wchodzą ani nie wychodzą z żadnych metod ramowych, które by to powodowały wymagają mostkowania do nich NSArray.

Robert Atkins
źródło
6
Czy próbowałeś dołączyć @objcdo swojego protokołu? stackoverflow.com/a/28029568/377369
Fabio Poloni
1
To nie działa, jeśli którakolwiek z implementacji protokołu jest wyliczeniem: „Typ nieklasowy„ Foo ”nie może być zgodny z protokołem klasy„ Opcja ””
Robert Atkins
Dlaczego jednak musi to być protokół klasowy? Nie przekazuję tego do frameworka Obj-C ani niczego innego, co wymaga mostkowania Swift Array do NSArray.
Robert Atkins
Sposób, w jaki Swift i Objective-C współpracują ze sobą, wciąż jest dla mnie tajemnicą. Muszę tylko „zaakceptować” wiele rzeczy, które po prostu „działają” lub „nie działają”.
Fabio Poloni
9
Dlaczego ten ma tyle głosów przeciw? Wydaje mi się, że to uczciwe i jasne pytanie.
Guven,

Odpowiedzi:

83

Znalazłem rozwiązanie. To dość ... niezadowalające , ale działa. Gdzie ustawiam tablicę na kontrolerze widoku docelowego, robię:

destinationViewController.options = options.map({$0 as Option})
Robert Atkins
źródło
nie możesz rzucić całej tablicy? options as [Option]
Kostiantyn Koval
Nie. Próbowałem (Xcode 6.3.1 (6D1002)), nie działa. W żadnym wypadku nie powinienem go rzucać, kompilator wie, że przekazuję tablicę rzeczy, które implementują Option.
Robert Atkins
2
„Tablica rzeczy, które implementują opcję” Ach, ale to nie jest to samo, co tablica opcji, której potrzebujesz. Zobacz moją odpowiedź.
mat
1
To działa i tak, jest bardzo niezadowalające ... to nie powinno być potrzebne. Szybki powinien sobie z tym poradzić.
Oscar Gomez
Zgadzam się ... to działa w ten sposób, ale jest to bardzo niezadowalający fragment kodu
Michael
22

kompilator wie, że przekazuję tablicę rzeczy, które implementują Option

Zostawiłeś tam bardzo odkrywczą uwagę, która sugeruje źródło problemu. „Tablica rzeczy, które implementują opcję” nie jest tablicą opcji.

Problem polega na tym, że typ optionspleców w miejscu, w którym je tworzysz (w formacieprepareForSegue ). Nie pokazujesz tego kodu, ale założę się, że nie możesz go rzucić / wpisać w tym momencie. Dlatego zadanie kończy się niepowodzeniem. optionsmoże być szereg rzeczy, które faktycznie zdarzają się w przypadku przyjęcia Option, ale to nie wystarczy; musi być wpisany jako tablica Option.

Więc wróć prepareForSegue, utwórz swój plikoptions następującą:

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

Teraz będziesz mógł przypisać go bezpośrednio do destinationViewController.options.

Oto krótki przypadek testowy (na placu zabaw; nie znoszę placów zabaw, ale mogą mieć swoje zastosowania):

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

(Przetestowałem to również w rzeczywistej aplikacji z rzeczywistym prepareForSeguei działa dobrze).

matowe
źródło
1
Myślę, że to jest podzielone w skrajności, ponieważ kompilator musi wiedzieć, że w czasie wykonywania Thing jest opcja. W każdym razie, jak zauważono w komentarzu do mojej własnej odpowiedzi poniżej, ani rzutowanie ( viewController.options = things as [Option]), ani tworzenie zmiennej tymczasowej jawnie wpisanej, jak [Option]sugerujesz tutaj, w rzeczywistości nie działa. W obu przypadkach pojawia się błąd wykonania.
Robert Atkins
Następnie musisz wyjaśnić, dlaczego to działa dla mnie. Dzieje się coś innego, czego nie powiedziałeś. Jeśli nie ujawnisz więcej kodu, po prostu muszę podejrzewać, że ukrywasz coś istotnego.
Mat
Może. Ale nadal nie wiem, co to ma wspólnego z Objective-C w pierwszej kolejności (w porównaniu z pierwotnym błędem wykonawczym). Nie robię niczego (co widzę), co powinno zmusić rzutowanie mostujące do NSArray.
Robert Atkins
2
Spójrz na to w ten sposób. Pokazałem Ci kod, który działa. Ty nie pokazano mi, że kod nie pracy - nie mogę reprodukowania problem z danych podanych. Pomóż mi to odtworzyć.
mat
1
@ CristiBăluță To jest to, czego powinieneś się dowiedzieć, zanim stwierdzisz, że „ten problem nadal nie jest rozwiązany”
mat.
16

Miałem ten sam problem i naprawiłem go przy oznaczaniu mojego protokołu @objc, w twoim przypadku wyglądałoby to tak

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

Mam rozwiązanie z tej odpowiedzi

Juan
źródło
1
Podobnie jak w komentarzach do pierwotnego pytania, nie działa to, jeśli którykolwiek z implementatorów protokołu jest Swift Enums. W moim przypadku tak jest.
Robert Atkins
typo obcj powinno być objc
Alan Scarpa
1

Ten również działa dobrze

destinationViewController.options = options.map{$0}
Mykoła Denysiuk
źródło