概述
- protocol類似C++中的抽象類和Java中的interface。分為Formal protocol和informal protocol兩種,其中在Objective C 2.0之前,informal protocol是Cocoa中實現delegate的重要基礎。因為Objective C 2.0引入了@optional和@required關鍵字。
- delegate是一種常用的設計模式,而不是Objective C或者Cocoa的feature,也沒有任何關鍵字是給delegate用的。
protocol
Formal protocol 聲明了一個客戶類需要實現的方法列表,它有自己獨立的declaration、adoption和類型檢查語法。這個方法列表中的方法可以使用@required @optional 標注,以表示該方法是否是客戶類必須要實現的方法。如果父類實現了某個formal protocol,那子類可以完全繼承其實現。Formal protocol可以繼承其他的Formal protocol。
Informal protocol是NSObject的category(見),並沒有獨立的聲明、采用和類型檢查的語法,跟普通的類和方法沒什么區別。在informal protocol中的方法其實現不是必須的。在invoke某個方法前,calling object需要檢查target object是否實現了這個方法。
下面是一個formal protocol的例子:
// declare 3 protocols in a.h file @protocol MSFormalProtocol <NSObject> @required - (void) foo; @end @protocol MSFormalProtocol2 <NSObject,MSFormalProtocol> @optional - (void) bar; @end @protocol MSFormalProtocol3 <NSObject> @end
//define the interface which adopt these 3 protocols @interface MSTestFormalProtocol : NSObject <MSFormalProtocol2,MSFormalProtocol3> @end //but we do not implement these required method @implementation MSTestFormalProtocol @end
從上面的例子可以看到,協議的adoption 語法是<Protocol1, [Protocol1,...]>。如果要聲明一個變量,它的要求是adopt某個/幾個protocol,那么其聲明語法可以如下所示:
id <MSFormalProtocol2> *ptr;
從NSTableViewDataSource 的聲明也可以看到這樣的例子。
@protocol NSTableViewDataSource <NSObject> @optional #pragma mark - #pragma mark ***** Required Methods (unless bindings are used) ***** - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView; /* This method is required for the "Cell Based" TableView, and is optional for the "View Based" TableView. If implemented in the latter case, the value will be set to the view at a given row/column if the view responds to -setObjectValue: (such as NSControl and NSTableCellView). */ - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; #pragma mark - #pragma mark ***** Optional Methods ***** /* NOTE: This method is not called for the View Based TableView. */ - (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; /* Sorting support This is the indication that sorting needs to be done. Typically the data source will sort its data, reload, and adjust selections. */ - (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray *)oldDescriptors; /* Dragging Source Support - Required for multi-image dragging. Implement this method to allow the table to be an NSDraggingSource that supports multiple item dragging. Return a custom object that implements NSPasteboardWriting (or simply use NSPasteboardItem). If this method is implemented, then tableView:writeRowsWithIndexes:toPasteboard: will not be called. */ - (id <NSPasteboardWriting>)tableView:(NSTableView *)tableView pasteboardWriterForRow:(NSInteger)row NS_AVAILABLE_MAC(10_7); /* Dragging Source Support - Optional. Implement this method to know when the dragging session is about to begin and to potentially modify the dragging session.'rowIndexes' are the row indexes being dragged, excluding rows that were not dragged due to tableView:pasteboardWriterForRow: returning nil. The order will directly match the pasteboard writer array used to begin the dragging session with [NSView beginDraggingSessionWithItems:event:source]. Hence, the order is deterministic, and can be used in -tableView:acceptDrop:row:dropOperation: when enumerating the NSDraggingInfo's pasteboard classes. */ - (void)tableView:(NSTableView *)tableView draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint forRowIndexes:(NSIndexSet *)rowIndexes NS_AVAILABLE_MAC(10_7); /* Dragging Source Support - Optional. Implement this method to know when the dragging session has ended. This delegate method can be used to know when the dragging source operation ended at a specific location, such as the trash (by checking for an operation of NSDragOperationDelete). */ - (void)tableView:(NSTableView *)tableView draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation NS_AVAILABLE_MAC(10_7); /* Dragging Destination Support - Required for multi-image dragging. Implement this method to allow the table to update dragging items as they are dragged over the view. Typically this will involve calling [draggingInfo enumerateDraggingItemsWithOptions:forView:classes:searchOptions:usingBlock:] and setting the draggingItem's imageComponentsProvider to a proper image based on the content. For View Based TableViews, one can use NSTableCellView's -draggingImageComponents. For cell based TableViews, use NSCell's draggingImageComponentsWithFrame:inView:. */ - (void)tableView:(NSTableView *)tableView updateDraggingItemsForDrag:(id <NSDraggingInfo>)draggingInfo NS_AVAILABLE_MAC(10_7); /* Dragging Source Support - Optional for single-image dragging. Implement this method to support single-image dragging. Use the more modern tableView:pasteboardWriterForRow: to support multi-image dragging. This method is called after it has been determined that a drag should begin, but before the drag has been started. To refuse the drag, return NO. To start a drag, return YES and place the drag data onto the pasteboard (data, owner, etc...). The drag image and other drag related information will be set up and provided by the table view once this call returns with YES. 'rowIndexes' contains the row indexes that will be participating in the drag. */ - (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard; /* Dragging Destination Support - This method is used by NSTableView to determine a valid drop target. Based on the mouse position, the table view will suggest a proposed drop 'row' and 'dropOperation'. This method must return a value that indicates which NSDragOperation the data source will perform. The data source may "re-target" a drop, if desired, by calling setDropRow:dropOperation: and returning something other than NSDragOperationNone. One may choose to re-target for various reasons (eg. for better visual feedback when inserting into a sorted position). */ - (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation; /* Dragging Destination Support - This method is called when the mouse is released over an NSTableView that previously decided to allow a drop via the validateDrop method. The data source should incorporate the data from the dragging pasteboard at this time. 'row' and 'dropOperation' contain the values previously set in the validateDrop: method. */ - (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation; /* Dragging Destination Support - NSTableView data source objects can support file promised drags by adding NSFilesPromisePboardType to the pasteboard in tableView:writeRowsWithIndexes:toPasteboard:. NSTableView implements -namesOfPromisedFilesDroppedAtDestination: to return the results of this data source method. This method should returns an array of filenames for the created files (filenames only, not full paths). The URL represents the drop location. For more information on file promise dragging, see documentation on the NSDraggingSource protocol and -namesOfPromisedFilesDroppedAtDestination:. */ - (NSArray *)tableView:(NSTableView *)tableView namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination forDraggedRowsWithIndexes:(NSIndexSet *)indexSet; @end
語法:
由於Objective-C 在編譯時不檢查方法是否存在,所以如果我們要求某個類滿足某個協議,由於不是強類型的,所以編譯器不檢查我們是否正確遵照這個協議實現了,從而導致錯誤。比如,NSTableView的datasource要求實現方法:
- (int) numberOfRowsInTableView:(NSTableView *)aTableView;
如果不小心寫錯了,比如少寫或者多寫了一個字母,那編譯時沒有任何錯誤,但是運行起來的時候,不work。