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

iOS 開發核心模式:Delegate 代理模式完整解析與實戰

     編輯:關於C

什麼是 Delegate 代理模式?

在 iOS / macOS 開發中,Delegate(代理)模式 是實現物件間「一對一」通訊的基石。它將「發生事件的物件(委託者)」與「處理事件的物件(代理者)」解耦:委託者只負責發送訊息,具體處理邏輯由遵循特定協議的代理者實現。幾乎所有 UIKit 元件(UITableView、UITextField、UIScrollView 等)都大量採用此模式。

核心三要素

  1. 協議:定義代理者需實作的方法清單(含 @required 必須實作與 @optional 可選實作)。
  2. 委託者持有弱引用:@property (nonatomic, weak) id<ProtocolName> delegate; 避免循環保留。
  3. 代理者遵循協議並實作方法:在介面宣告加上 <ProtocolName>,並實作對應方法。

實戰範例:狗與主人的定時通訊

場景:Dog 每秒吠叫一次,透過代理通知 Person 目前吠叫次數。

1. 定義協議

// DogBarkProtocol.h
#import 
@class Dog; // 前向宣告

@protocol DogBarkProtocol 
@optional
- (void)dog:(Dog *)dog didBarkWithCount:(NSInteger)count;
@end

2. 委託者 Dog

// Dog.h
#import 
@protocol DogBarkProtocol;

@interface Dog : NSObject
@property (nonatomic, assign) NSInteger dogID;
@property (nonatomic, weak) id delegate;
- (instancetype)initWithID:(NSInteger)id;
@end

// Dog.m
#import "Dog.h"
#import "DogBarkProtocol.h"

@implementation Dog {
    NSTimer *_timer;
    NSInteger _barkCount;
}
- (instancetype)initWithID:(NSInteger)id {
    self = [super init];
    if (self) {
        _dogID = id;
        _barkCount = 0;
        _timer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                  target:self
                                                selector:@selector(timerFired:)
                                                userInfo:nil
                                                 repeats:YES];
    }
    return self;
}
- (void)timerFired:(NSTimer *)timer {
    _barkCount++;
    if ([self.delegate respondsToSelector:@selector(dog:didBarkWithCount:)]) {
        [self.delegate dog:self didBarkWithCount:_barkCount];
    }
}
- (void)dealloc {
    [_timer invalidate];
    _timer = nil;
}
@end

3. 代理者 Person

// Person.h
#import 
@class Dog;
#import "DogBarkProtocol.h"

@interface Person : NSObject 
@property (nonatomic, strong) Dog *dog;
@end

// Person.m
#import "Person.h"
#import "Dog.h"

@implementation Person
- (void)dog:(Dog *)dog didBarkWithCount:(NSInteger)count {
    NSLog(@"主人收到通知:狗 %ld 第 %ld 次吠叫", (long)dog.dogID, (long)count);
}
@end

4. 主程式串聯

// main.m
#import 
#import "Person.h"
#import "Dog.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *owner = [[Person alloc] init];
        Dog *dog = [[Dog alloc] initWithID:1024];
        dog.delegate = owner;      // 關鍵:設定代理
        owner.dog = dog;           // 可選:主人持有狗的強引用
        
        // 保持 RunLoop 運作以接收 Timer 事件
        [[NSRunLoop currentRunLoop] run];
    }
    return 0;
}

關鍵細節與避坑指南

  • weak vs assign:ARC 環境下請用 weak;MRC 時代用 assign,並在 dealloc 中置 nil。
  • 前向宣告 @class / @protocol:解決循環引用導致的編譯錯誤。
  • respondsToSelector: 呼叫 @optional 方法前務必檢查,防止未實作導致崩潰。
  • RunLoop:命令列專案需手動跑 [[NSRunLoop currentRunLoop] run],否則 Timer 不會觸發。

擴展:多重代理與 Block 回調替代

若需「一對多」通知,請改用 NSNotificationCenter 或 Combine 框架;簡單單次回調場景可考慮 Block(見下一篇「Blocks 應用」),但 Delegate 仍是建立長期、結構化協作關係的最佳選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved