首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Objective-C 代理模式深度解析:delegate 機制、協議與跨語言對比

     編輯:關於C語言

代理模式是 Cocoa 框架的核心設計範式,貫穿 UI 交互、網絡請求、數據源驅動等所有異步協作場景。本文從協議定義、注入機制、運行時流程、與 Java Listener/C++ 虛函數的對比五個維度,建立完整的 delegate 認知體系。

一、協議與代理的關係

  • 協議:語言級特性,定義「能響應哪些消息」的契約 (@protocol)。
  • 代理:設計模式,將具體實現委託給外部對象,實現「控制反轉」。
  • 關係:代理對象 遵守 協議;委託者持有 id 類型引用。

二、UIActionSheet 經典案例拆解

// 協議定義 (簡化)
@protocol UIActionSheetDelegate 
@optional
- (void)actionSheet:(UIActionSheet*)sheet clickedButtonAtIndex:(NSInteger)idx;
- (void)actionSheetCancel:(UIActionSheet*)sheet;
- (void)willPresentActionSheet:(UIActionSheet*)sheet;
- (void)didPresentActionSheet:(UIActionSheet*)sheet;
- (void)actionSheet:(UIActionSheet*)sheet willDismissWithButtonIndex:(NSInteger)idx;
- (void)actionSheet:(UIActionSheet*)sheet didDismissWithButtonIndex:(NSInteger)idx;
@end

// 初始化時注入代理
UIActionSheet *sheet = [[UIActionSheet alloc] 
    initWithTitle:@"Title" 
    delegate:self  // self 遵守 UIActionSheetDelegate
    cancelButtonTitle:@"取消"
    destructiveButtonTitle:@"確定"
    otherButtonTitles:@"項目一", @"項目二", nil];
[sheet showInView:self.view];

關鍵點

  1. @optional 方法無需全部實現,運行時以 respondsToSelector: 動態檢查。
  2. 代理屬性通常用 assign (MRC) / weak (ARC) 避免循環引用。
  3. 按鈕索引對應 otherButtonTitles 順序,取消按鈕固定為最後一個。

三、最小化代理模式手動實現

// 1. 定義協議
@protocol ButtonClickDelegate 
- (void)onClick:(id)sender;
@end

// 2. 被委託者
@interface UIView : NSObject 
@property (nonatomic, weak) id clickDelegate;
- (void)performClick;
@end

@implementation UIView
- (instancetype)init {
    if ((self = [super init])) {
        _clickDelegate = self;  // 默認自我代理
    }
    return self;
}
- (void)onClick:(id)sender { NSLog(@"View 默認處理"); }
- (void)performClick { [_clickDelegate onClick:self]; }
@end

// 3. 委託者/控制器
@interface ViewController : NSObject 
@property (nonatomic, strong) UIView *contentView;
@end

@implementation ViewController
- (void)onClick:(id)sender { NSLog(@"Controller 處理點擊"); }
@end

// 4. 運行時切換
int main() {
    @autoreleasepool {
        UIView *view = [[UIView alloc] init];
        [view performClick];  // 輸出: View 默認處理
        
        ViewController *vc = [[ViewController alloc] init];
        view.clickDelegate = vc;  // 注入外部代理
        [view performClick];      // 輸出: Controller 處理點擊
    }
}

四、跨語言對比:本質同構

Android 對應代碼

Button btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
        startActivity(new Intent(this, SecondActivity.class));
    }
});

Button ↔ UIView,setOnClickListener ↔ delegate 屬性,OnClickListener ↔ ButtonClickDelegate,onClick 完全對應。

五、id 與泛型的類比

// Objective-C
@property (nonatomic, weak) id clickDelegate;

// Java 泛型對應
void setClickListener(ButtonClickListener listener);  // 單一類型
// 或更泛化
 void setClickListener(T listener);

id 表達:「任意類型,但必須遵守 Protocol」。這是動態類型系統的「結構化子類型」約束,編譯器會檢查實現完整性(@required 方法),運行時再動態分發。

六、工程最佳實踐

  1. 代理屬性必須 weak/assign:打破保留環,防洩漏。
  2. 協議方法盡量 @optional:降低實現負擔,運行時 respondsToSelector: 守衛。
  3. 命名規範:- (void)tableView:(UITableView*)tv didSelectRowAtIndexPath:(NSIndexPath*)ip; 首參數為發送者,便於多對一代理區分來源。
  4. 多代理場景:使用 NSNotificationCenter、RxSwift、Combine 替代單播代理。
  5. Swift 互操作:@objc protocol 供 OC 調用,Swift 類用 weak var delegate: Protocol?。

代理模式的核心是「行為參數化」:將「做什麼」內化為協議契約,將「誰來做」外部化為運行時注入。這不僅是 Cocoa 的靈魂,更是所有事件驅動架構的通用範式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
概念Objective-CJava (Android)C#C++
契約@protocolinterfaceinterface純虛類/Concept
代理引用id / weakListener 引用delegate 關鍵字 / eventstd::function / 虛函數
注入屬性賦值setOnClickListener+= 運算符構造函數/Setter
調用[delegate onClick:self]listener.onClick(v)delegate.Invoke()callback() / virt_func()
多播需手動實現 (NotificationCenter)單播為主事件原生支持多播signal/slot 或多播委託