2009-06-13 12 views

Odpowiedz

80

Po pierwsze, trochę historical perspective on the topic, od jednego z twórców Javy. Dalej Wikipedia ma umiarkowanie pomocne section on Objective-C protocols. W szczególności należy zrozumieć, że Objective-C obsługuje zarówno formalne protokoły (które są jawnie zadeklarowane za pomocą słowa kluczowego @protocol, odpowiednik interfejsu Java), jak i nieformalnych protokołów (tylko jedna lub więcej metod zaimplementowanych przez klasę, które mogą być odkryta poprzez odbicie).

Jeśli przyjmiesz formalny protokół (terminologia Objective-C dla "implementowania interfejsu") kompilator będzie wysyłać ostrzeżenia o metodach niezaimplementowanych, tak jak można by oczekiwać w Javie. przeciwieństwie Java (jak skaffman wymienionych), jeśli klasa Objective-C implementuje metody zawarte w oficjalnym protokole, to mówi się, że „zgodne” do tego protokołu, nawet jeśli jego interfejs wyraźnie nie przyjmuje go. można przetestować protokołu zgodności w kodzie (używając -conformsToProtocol:) tak:

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

UWAGA: Apple documentation stany:

„Metoda ta określa zgodność wyłącznie na podstawie formalnych zgłoszeń w plikach nagłówkowych , jak pokazano powyżej, nie sprawdza, czy metody zadeklarowane w protokole są faktycznie zaimplementowane - to odpowiedzialność programisty. "

W Celu-C 2.0 (Os X 10,5 „Leoparda” i OI) protokoły formalne mogą określić fakultatywne metody i klasa zgodnym z protokołem, pod warunkiem, że wprowadza wszystkie wymagane metody . Można użyć słów kluczowych @required (domyślnie) i @optional, aby przełączyć, czy deklaracje metod następujące po tej procedurze muszą być zaimplementowane, aby były zgodne z protokołem. (Zobacz rozdział przewodnika Apple Objective-C 2.0 Programming Language, który omawia optional protocol methods.)

Opcjonalne metody protokołu otworzyć dużą elastyczność dla programistów, w szczególności za realizację delegatów i słuchaczy. Zamiast rozszerzania czegoś takiego jak MouseInputAdapter (co może być denerwujące, ponieważ Java jest również dziedziczeniem pojedynczym) lub implementowania wielu bezcelowych, pustych metod, możesz przyjąć protokół i wdrożyć tylko te opcjonalne metody, na których ci zależy. Z tego wzoru, dzwoniący sprawdza, czy metoda jest realizowana przed wywołaniem go (używając -respondsToSelector) tak:

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

Jeśli napowietrznej refleksji staje się problemem, zawsze można cache the boolean result for reuse, ale oprzeć się pokusie, aby zoptymalizować przedwcześnie . :-)

+4

"Jeśli przyjmiesz formalny protokół (terminologia Objective-C dla" implementowania interfejsu ") kompilator będzie wysyłać ostrzeżenia o metodach niezaimplementowanych, tak jak można by oczekiwać w Javie." W tym przypadku Java wyśle ​​błąd, a nie ostrzeżenie. –

+3

"jeśli klasa Objective-C implementuje metody zawarte w formalnym protokole, mówi się, że" dostosowuje się "do tego protokołu, nawet jeśli jego interfejs nie przyjmuje go jawnie.Możesz przetestować zgodność protokołu w kodzie (używając -conformsToProtocol :) tak: "To jest FAŁSZ. '-conformsToProtocol:' zwróci tylko TAK, jeśli klasa jawnie przyjmie ten protokół. Czy próbowałeś tego? – user102008

+2

Masz rację, '-conformsToProtocol:' rzeczywiście wymaga, aby klasa (lub przodek) formalnie zadeklarowała przyjęcie protokołu. Nie wiem, jak źle to zrobiłem, dzięki za poprawkę! –

18

Są prawie identyczne. Jednak jedną rzecz, która mnie zaskoczyła, jest to, że dopóki wyraźnie nie zadeklarujesz, że obiektywny protokół C również implementuje NSObject, odniesienia do tego protokołu nie dają dostępu do metod deklarowanych przez NSObject (bez ostrzeżenia kompilatora). W java możesz mieć odwołanie do interfejsu i wciąż wywoływać toString() itd.

np

Cel C:

@protocol MyProtocol 
// Protocol definition 
@end 

id <MyProtocol> myProtocol; 

[myProtocol retain] // Compiler warning 

Java:

public interface MyInterface { 
// interface definition 
} 

MyInterface myInterface; 

myInterface.toString(); // Works fine. 

Cel C (stałej)

@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 obiektem głównym jest Object. W Objective-C obiekt NSObject jest obiektem głównym, ale nie * obiektem głównym. Jeśli chcesz uzyskać dostęp do wszystkich metod NSObject (metody klasy, a także protokoły), jawnie określ to: NSObject myProtocol; zamiast: id ... Kiedy używasz id, mówisz: nie obchodzi mnie obiekt, * tylko * protokół, co w twoim przypadku nie jest prawdą. –

+0

@JasonCoco cool: D – hqt

Powiązane problemy