2009-06-13 30 views

Trả lời

80

Trước hết, một chút historical perspective on the topic, từ một trong những người tạo Java. Tiếp theo, Wikipedia có mức độ hữu ích vừa phải section on Objective-C protocols. Đặc biệt, hiểu rằng Objective-C hỗ trợ cả hai giao thức chính thức (được khai báo rõ ràng với từ khóa @protocol, tương đương với giao diện Java) và giao thức không chính thức (chỉ một hoặc nhiều phương thức được thực hiện bởi một lớp) được phát hiện qua sự phản chiếu).

Nếu bạn áp dụng giao thức chính thức (thuật ngữ Objective-C để "triển khai giao diện") trình biên dịch sẽ phát ra cảnh báo cho các phương thức chưa thực hiện, giống như bạn mong đợi trong Java. Không giống như Java (như skaffman được đề cập), nếu một lớp Objective-C thực hiện các phương thức chứa trong một giao thức chính thức, nó được gọi là "tuân thủ" giao thức đó, ngay cả khi giao diện của nó không chấp nhận nó một cách rõ ràng. Bạn có thể kiểm tra giao thức phù hợp trong mã (sử dụng -conformsToProtocol:) như thế này:

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

LƯU Ý: Apple documentation trạng thái:

"Phương pháp này xác định sự phù hợp hoàn toàn trên cơ sở tờ khai chính thức trong các tập tin tiêu đề , như minh họa ở trên. Nó không kiểm tra xem liệu các phương thức được khai báo trong giao thức có thực sự được triển khai hay không - đó là trách nhiệm của lập trình viên. "

Tính đến Objective-C 2.0 (trong OS X 10.5 "Leopard" và iOS), các giao thức chính thức bây giờ có thể xác định phương pháp bắt buộc, và một lớp học phù hợp với một giao thức miễn là nó thực hiện tất cả các phương pháp cần thiết . Bạn có thể sử dụng các từ khóa @required (mặc định) và @optional để chuyển đổi xem các khai báo phương pháp theo sau phải hoặc có thể được triển khai để phù hợp với giao thức hay không. (Xem phần hướng dẫn của Objective-C 2.0 Programming Language của Apple thảo luận về optional protocol methods.)

phương pháp giao thức bắt buộc mở ra rất nhiều sự linh hoạt để phát triển, đặc biệt đối với việc thực hiện đại biểunghe. Thay vì mở rộng một cái gì đó giống như một MouseInputAdapter (có thể gây phiền toái, vì Java cũng là thừa kế đơn) hoặc thực hiện rất nhiều phương thức vô nghĩa, trống rỗng, bạn có thể áp dụng một giao thức và chỉ thực hiện các phương thức tùy chọn mà bạn quan tâm. Với mô hình này, người gọi kiểm tra xem phương pháp này được thực hiện trước khi gọi nó (sử dụng -respondsToSelector) như sau:

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

Nếu overhead phản xạ trở thành một vấn đề, bạn có thể luôn luôn cache the boolean result for reuse, nhưng cưỡng lại sự thôi thúc để tối ưu hóa sớm . :-)

+4

"Nếu bạn áp dụng một giao thức chính thức (thuật ngữ Objective-C để" thực hiện một giao diện ") trình biên dịch sẽ phát ra cảnh báo cho các phương thức chưa thực hiện, giống như bạn mong đợi trong Java." Java sẽ phát ra một lỗi trong trường hợp này, không phải là một cảnh báo. –

+3

"nếu một lớp Objective-C thực hiện các phương thức chứa trong một giao thức chính thức, nó được cho là" phù hợp "với giao thức đó, ngay cả khi giao diện của nó không chấp nhận nó một cách rõ ràng. :) như thế này "Đây là FALSE. '-conformsToProtocol:' sẽ chỉ trả về YES nếu lớp đó thông qua giao thức một cách rõ ràng. Bạn đã thử nó chưa? – user102008

+2

Bạn đúng, '-conformsToProtocol:' thực sự yêu cầu rằng lớp (hoặc tổ tiên) chính thức tuyên bố rằng nó thông qua giao thức. Không chắc chắn làm thế nào tôi đã nhận sai, nhờ sự điều chỉnh! –

18

Chúng gần như giống hệt nhau. Tuy nhiên, một điều mà đã bắt được tôi, trừ khi bạn khai báo rõ ràng rằng một giao thức C đích cũng thực thi NSObject, các tham chiếu tới giao thức đó không nhận được quyền truy cập vào các phương thức mà NSObject khai báo (không có cảnh báo trình biên dịch). Với java bạn có thể có một tham chiếu đến một giao diện, và vẫn gọi toString() vv trên đó.

ví dụ

Objective 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. 

Objective C (cố định):

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

id <MyProtocol> myProtocol; 

[myProtocol retain] // No Warning 
+25

Điều này là do id và NSObject * không giống nhau *. Trong Java, đối tượng gốc là Object. Trong Objective-C, NSObject là một đối tượng gốc, nhưng không phải là đối tượng gốc *. Nếu bạn muốn truy cập vào tất cả các phương thức NSObject (các phương thức lớp cũng như các giao thức), hãy nêu rõ điều này: NSObject myProtocol; thay vì: id ... Khi bạn sử dụng id bạn đang nói: Tôi không quan tâm đến đối tượng, * chỉ * giao thức mà trong trường hợp của bạn không đúng. –

+0

@JasonCoco cool: D – hqt

Các vấn đề liên quan