Protocol(協議) 本質是一組方法清單,聲明了「能做什麼」,不關心「怎麼做」。任何類別只要實現協議中的方法,就宣稱遵循該協議。在 iOS/macOS 開發中,Apple 大量採用委託模式解耦 View 與 Controller,這正是 Protocol 的經典應用場景。
Android 中按鈕點擊採用介面回調:
// 1. 定義介面
public interface OnClickListener {
void onClick(View v);
}
// 2. View 持有介面引用
public void setOnClickListener(OnClickListener l) {
if (!isClickable()) setClickable(true);
getListenerInfo().mOnClickListener = l;
}
// 3. Activity 實現介面並註冊
button.setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) { ... }
});
核心機制:View 內部維護 ListenerInfo 對象,將監聽器保存;事件分發時調用 onClick。這是典型的「介面+回調」解耦。
Objective-C 用 @protocol 定義協議,用 id<Protocol> 持有委託對象,respondsToSelector: 動態檢查方法實現——這比 Java 介面更靈活(可選方法、運行時檢查)。
Button.h —— 定義兩個協議與委託屬性
#import <Foundation/Foundation.h> @class Button; @protocol ButtonDelegate <NSObject> - (void)onClick:(Button *)btn; @end @protocol ButtonLongClickDelegate <NSObject> - (void)onLongClick:(Button *)btn; @end @interface Button : NSObject @property (nonatomic, retain) id<ButtonDelegate> delegate; @property (nonatomic, retain) id<ButtonLongClickDelegate> longClickDelegate; // 模擬系統觸發 - (void)click; - (void)longClick; @end
Button.m —— 觸發時安全調用
#import "Button.h"
@implementation Button
- (void)click {
if ([_delegate respondsToSelector:@selector(onClick:)]) {
[_delegate onClick:self];
} else {
NSLog(@"onClick 委託未實現");
}
}
- (void)longClick {
if ([_longClickDelegate respondsToSelector:@selector(onLongClick:)]) {
[_longClickDelegate onLongClick:self];
} else {
NSLog(@"longClick 委託未實現");
}
}
- (void)dealloc {
[_delegate release];
[_longClickDelegate release];
[super dealloc];
}
@end
委託實現類(分離關注點)
// ButtonListener.m
- (void)onClick:(Button *)btn { NSLog(@"按鈕被點擊了"); }
// ButtonLongClickListener.m
- (void)onLongClick:(Button *)btn { NSLog(@"按鈕被長按了"); }
Main.m —— 組裝
int main() {
@autoreleasepool {
Button *button = [[[Button alloc] init] autorelease];
ButtonListener *listener = [[[ButtonListener alloc] init] autorelease];
ButtonLongClickListener *longListener = [[[ButtonLongClickListener alloc] init] autorelease];
button.delegate = listener;
button.longClickDelegate = longListener;
[button click]; // 輸出:按鈕被點擊了
[button longClick]; // 輸出:按鈕被長按了
}
return 0;
}
| 維度 | Android (Interface) | iOS (Protocol + Delegate) |
|---|---|---|
| 定義方式 | interface 關鍵字 | @protocol 指令 |
| 方法屬性 | 全部強制實現(Java 8 前) | 可標記 @optional,運行時用 respondsToSelector: 判斷 |
| 持有引用 | 強引用(需注意洩漏) | 通常 weak/assign 避免循環引用 |
| 多委託 | 單介面多方法或多介面 | 多個 @protocol + 多個 delegate 屬性 |
weak (ARC) 或 assign (MRC) 打破循環引用。<NSObject> 可獲得 respondsToSelector: 等基礎方法。(Button *)btn),方便委託識別來源。通過對比 Android 介面回調與 iOS Protocol/Delegate,可以清晰看到兩種平台對「解耦」的不同哲學:前者靠靜態類型檢查,後者靠動態消息轉發。理解這一點,能幫助你在跨平台架構設計時做出更合理的抽象決策。