Różnice między interfejsami Java a protokołami Objective-C?


93

Znam Javę, a teraz uczę się Objective-C. Jakie dokładnie są różnice między interfejsami Java a protokołami Objective-C?

Odpowiedzi:


82

Na początek trochę historycznego spojrzenia na temat od jednego z twórców Javy. Następnie Wikipedia ma średnio przydatną sekcję dotyczącą protokołów Objective-C . W szczególności zrozum, że Objective-C obsługuje zarówno formalne protokoły (które są wyraźnie zadeklarowane za pomocą @protocolsłowa kluczowego, odpowiednik interfejsu Java), jak i nieformalne protokoły (tylko jedna lub więcej metod implementowanych przez klasę, które można wykryć poprzez odbicie).

Jeśli zastosujesz formalny protokół (terminologia Objective-C dla „implementacji interfejsu”), kompilator wyemituje ostrzeżenia o niezaimplementowanych metodach, tak jak można się tego spodziewać w Javie. W przeciwieństwie do Javy (jak wspomniał skaffman ), jeśli klasa Objective-C implementuje metody zawarte w formalnym protokole, mówi się, że „jest zgodna” z tym protokołem, nawet jeśli jej interfejs wyraźnie go nie przyjmuje.Możesz przetestować zgodność protokołu w kodzie (używając -conformsToProtocol:) w następujący sposób:

if ([myObject conformsToProtocol:@protocol(MyProtocol)]) {
    ...
}

UWAGA: Dokumentacja Apple stwierdza:

„Ta metoda określa zgodność wyłącznie na podstawie formalnych deklaracji w plikach nagłówkowych, jak pokazano powyżej. Nie sprawdza, czy metody zadeklarowane w protokole są rzeczywiście zaimplementowane - za to odpowiada programista”.

Od wersji Objective-C 2.0 (w OS X 10.5 „Leopard” i iOS) formalne protokoły mogą teraz definiować metody opcjonalne , a klasa jest zgodna z protokołem, o ile implementuje wszystkie wymagane metody. Możesz użyć słów kluczowych @required(domyślnych) i, @optionalaby przełączyć, czy deklaracje metod, które następują, muszą lub mogą być zaimplementowane w celu zgodności z protokołem. (Zobacz sekcję podręcznika języka programowania Objective-C 2.0 firmy Apple, w którym omówiono opcjonalne metody protokołów ).

Opcjonalne metody protokołów zapewniają programistom dużą elastyczność, szczególnie w zakresie implementowania delegatów i słuchaczy . Zamiast rozszerzać coś w rodzaju MouseInputAdapter (co może być denerwujące, ponieważ Java jest również dziedziczeniem pojedynczym) lub implementować wiele bezcelowych, pustych metod, możesz przyjąć protokół i zaimplementować tylko te opcjonalne metody, na których Ci zależy. W przypadku tego wzorca obiekt wywołujący sprawdza, czy metoda jest zaimplementowana przed jej wywołaniem (przy użyciu -respondsToSelector ), tak jak poniżej :

if ([myObject respondsToSelector:@selector(fillArray:withObject:)]) {
    [myObject fillArray:anArray withObject:foo];
    ...
}

Jeśli narzut odbicia stanie się problemem, zawsze możesz buforować wynik boolowski w celu ponownego wykorzystania , ale powstrzymaj się przed przedwczesną optymalizacją. :-)


4
„Jeśli zastosujesz formalny protokół (terminologia Objective-C dla„ implementacji interfejsu ”), kompilator wyemituje ostrzeżenia o niezaimplementowanych metodach, tak jak można by oczekiwać w Javie. W takim przypadku Java wyemituje błąd, a nie ostrzeżenie.
— Raffi Khatchadourian,

3
„Jeśli klasa Objective-C implementuje metody zawarte w formalnym protokole, mówi się, że jest„ zgodna ”z tym protokołem, nawet jeśli jej interfejs wyraźnie go nie przyjmuje. Możesz przetestować zgodność protokołu w kodzie (używając -conformsToProtocol: ) w ten sposób „This is FALSE. -conformsToProtocol:zwróci TAK tylko wtedy, gdy klasa jawnie przyjmie protokół. Czy nawet tego próbowałeś?
— user102008

2
Masz rację, -conformsToProtocol:rzeczywiście wymaga, aby klasa (lub przodek) formalnie zadeklarowała, że ​​przyjmuje protokół. Nie wiem, jak to źle zrozumiałem, dzięki za korektę!
— Quinn Taylor

18

Są prawie identyczne. Jednak jedyną rzeczą, która mnie złapała, jest to, że jeśli wyraźnie nie zadeklarujesz, że obiektywny protokół C również implementuje NSObject, odniesienia do tego protokołu nie uzyskują dostępu do metod deklarowanych przez NSObject (i tak bez ostrzeżenia kompilatora). Dzięki java możesz mieć odniesienie do interfejsu i nadal wywoływać na nim toString () itp.

na przykład

Cel C:

@protocol MyProtocol
// Protocol definition
@end

id <MyProtocol> myProtocol;

 [myProtocol retain] // Compiler warning

Jawa:

public interface MyInterface {
// interface definition
}

MyInterface myInterface;

myInterface.toString();  // Works fine.

Cel C (naprawiony):

@protocol MyProtocol <NSObject>
// Protocol definition
@end

id <MyProtocol> myProtocol;

[myProtocol retain] // No Warning

25
Dzieje się tak, ponieważ id i NSObject nie są takie same . W Javie głównym obiektem jest Object. W Objective-C, NSObject jest obiektem głównym, ale nie jest obiektem głównym. Jeśli chcesz mieć dostęp do wszystkich metod NSObject (metod klasowych oraz protokołów), powiedz to wyraźnie: NSObject <MyProtocol> myProtocol; zamiast: id <MyProtocol> ... Używając id mówisz: nie obchodzi mnie obiekt, tylko protokół, co w twoim przypadku nie jest prawdą.
— Jason Coco
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.