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?

Arne Evertsson
źródło

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ą. :-)

Quinn Taylor
źródło
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
Tom Jefferys
źródło
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