2015-09-21 12 views
10

Praca w mieszanym środowisku. importowane do pliku Obj-C, ale klasy wewnętrzne nie są widoczne, tylko te publiczne.Jak uzyskać dostęp do wewnętrznej klasy Swift w Objective-C w tych samych ramach?

Dokumentacja wyraźnie stwierdza wewnętrzne clasees powinna być dostępna między Swift i Obj-C:

Importowanie Swift w Objective-C
Aby zaimportować zestaw plików Swift w tym samym celu ramowego jako swój Kod Objective-C, nie musisz importować niczego do nagłówka parasolowego dla frameworka. Zamiast tego zaimportuj plik nagłówkowy wygenerowany przez Xcode dla kodu Swift do dowolnego pliku Objective-C .m, z którego chcesz użyć kodu Swift. Ponieważ wygenerowany nagłówek dla obiektu docelowego ramek jest częścią interfejsu publicznego frameworka , w wygenerowanym nagłówku dla obiektu ramowego pojawiają się tylko deklaracje oznaczone publicznym modyfikatorem . Ty mogą nadal korzystać Swift metod i właściwości, które są oznaczone wewnętrznym modyfikatora od wewnątrz części Objective-C swojej ramy, jak długo są one zgłaszane w ramach klasy, która dziedziczy z klasy Objective-C . Aby uzyskać więcej informacji na temat modyfikatorów poziomu dostępu, zobacz Access Control w The Swift Programming Language (Swift 2).

Przykładowy kod (Utwórz nowy projekt z ram)

// SwiftObject.swift 

public class SwiftObject: NSObject { 
    public class func doSomething() {} 
} 

internal class YetAnotherSwiftObject: NSObject { 
    internal class func doSomething() {} 
} 

// SomeObject.m file 

@implementation SomeObject 

- (void)someMethod { 
    [SwiftObject doSomething]; 
} 

- (void)someOtherMethod { 
    [YetAnotherSwiftObject doSomething]; // Use of undeclared identifier 
} 

@end 

Odpowiedz

16

Jak wskazano w docs, deklaracje oznaczone internal modyfikatora nie pojawiają się w wygenerowanym nagłówek, więc kompilator nie wie o nich, a więc skargi. Oczywiście można wysyłać wiadomości przy użyciu podejścia performSelector, ale to nie jest wygodne i podatne na błędy. Po prostu musimy pomóc kompilatorowi wiedzieć, że tam są te deklaracje.

Po pierwsze, musimy użyć @objc wariant atrybutu, który pozwala określić nazwę dla symbolu w Objective-C:

// SwiftObject.swift 

@objc(SWIFTYetAnotherSwiftObject) 
internal class YetAnotherSwiftObject: NSObject { 
    internal class func doSomething() {} 
} 

A potem po prostu trzeba utworzyć @interface deklarację z metodami, które chcesz użyć w kodzie - tak kompilator będzie zadowolony, a także zastosowanie SWIFT_CLASS makro z nazwą określonego symbolu już wcześniej - tak łącznik wybrałoby rzeczywistej realizacji:

// SomeObject.m file 

SWIFT_CLASS("SWIFTYetAnotherSwiftObject") 
@interface YetAnotherSwiftObject : NSObject 

+ (void)doSomething; 

@end 


@implementation SomeObject 

- (void)someOtherMethod { 
    [YetAnotherSwiftObject doSomething]; // Should work now !!! 
} 

@end 
  • Użyłem deklaracji interfejsu w pliku .m dla jasności, lepszym rozwiązaniem byłoby połączenie takich deklaracji w pliku .h i włączenie go.
  • Deklarując metody w tym interfejsie, składamy obietnicę kompilatorowi i nie będziemy narzekać, jeśli umieścisz tam metodę, która nie istnieje (lub z niewłaściwym podpisem itp.). Oczywiście, awaria w czasie wykonywania - więc bądź ostrożny.
+0

Nice! Nie wiedziałem o tym makro, a google niewiele pokazuje. Czy masz jakieś odniesienia z dokumentów Apple? – Yariv

+4

Nice? To jest okropnie gadatliwe i nieporządne. Czy to naprawdę jest to, co musisz zrobić? Wpadłem na ten sam problem, a nawet jabłko powinno było zrobić coś lepszego. Porzucę to i wrócę do obiektywnego c, to nierozsądne! +1 za opublikowanie czegoś, co faktycznie działa (po wielu godzinach wyszukiwania). –

+3

Zgodnie z dokumentacją firmy Apple "Nadal możesz używać metod i właściwości Swift oznaczonych wewnętrznym modyfikatorem z części Objective-C struktury, o ile są one zadeklarowane w klasie dziedziczącej po klasie Objective-C", jeśli klasa swift wywodzi się z innej klasy objc, powinna być dostępna w kodzie objc. Mam podobny problem i zaznaczyłem moją szybką klasę przez @objc i dziedziczy po NSObject, ale nadal nie jest dostępny w kodzie objc. – puru020

3

Dla mnie po prostu zadziałało, sprawdzając: "Zezwalaj tylko na rozszerzenie API aplikacji".Znajdziesz go, przechodząc do ustawień projektu, wybierz cel, a następnie na karcie Ogólne w obszarze Informacje o wdrażaniu.

Czy ktoś może mi wyjaśnić, dlaczego to rozwiązuje problem?

+0

Kocham cię! LOL . To jedyne miejsce na ziemi, które znalazło odpowiedź, by ominąć to głupie ograniczenie. Żadne ramy nie powinny być wymagane, aby ujawnić swoje klasy Swift konsumentom API tylko po to, aby móc współdziałać z wewnętrznym kodem ObjC! – nobre

+0

Uważaj na tę opcję! Zostanie wyświetlona lista klas i metod w nagłówku generowanym automatycznie. Używaj go tylko wtedy, gdy nie zależy ci na zachowaniu prywatności. – Amit

+0

Ale z tym zaznaczonym, będzie brakować garstki API kakao. – Martin

Powiązane problemy