委托模式是 Objective-C 中核心設計模式,通過協議定義契約,委托對象實現具體行為。本文通過「牛仔救姑娘」的生動故事,完整演示委托模式的設計與實現。
Wanted)Girl)聲明 id <Wanted> delegateCowboy)實現協議方法girl.delegate = cowboy[delegate saveHerDad]
// Wanted.h
#import <Foundation/Foundation.h>
@protocol Wanted <NSObject>
@required
- (int)saveHerDad; // 救父親
- (void)killTheBadGuy; // 殺壞人
@end
// Girl.h
#import <Foundation/Foundation.h>
#import "Wanted.h"
@interface Girl : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) id <Wanted> delegate;
- (instancetype)initWithName:(NSString*)name WithDelegate:(id<Wanted>)delegate;
- (void)helpHelp; // 觸發求救
@end
// Girl.m
#import "Girl.h"
#import "Cowboy.h"
@interface Girl ()
- (void)seesTheCowboy:(NSTimer *)timer;
@end
@implementation Girl
- (instancetype)initWithName:(NSString*)name WithDelegate:(id<Wanted>)delegate {
self = [super init];
if (self) {
self.name = name;
self.delegate = delegate; // 關鍵:設置委托
}
return self;
}
- (void)helpHelp {
NSLog(@"%@: My name is %@, my dad was taken by bad guys, can you save him?", self.name, self.name);
NSLog(@"%@: OK young lady, wait for good news!", self.delegate);
// 2秒一次檢查營救進度
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(seesTheCowboy:) userInfo:@"My dad" repeats:YES];
}
- (void)seesTheCowboy:(NSTimer *)timer {
if ([self.delegate respondsToSelector:@selector(saveHerDad)]) {
int result = [self.delegate saveHerDad];
if (result == 0) {
NSLog(@"%@: My heart is broken, you must save him!", self.name);
} else {
NSLog(@"%@: Thank you so much, marry me~", self.name);
[timer invalidate]; // 成功則停止定時器
}
}
}
@end
// Cowboy.h
#import <Foundation/Foundation.h>
@interface Cowboy : NSObject
@property (nonatomic, copy) NSString *name;
@end
// Cowboy.m
#import "Cowboy.h"
@implementation Cowboy
static int result = 0; // 靜態變量模擬營救進度
- (int)saveHerDad {
printf("\n");
result = [self killTheBadGuy];
if (result == 0) {
NSLog(@"%@: Too many of them, I'll gather my men!", self.name);
result++;
return 0; // 第一次失敗
} else {
NSLog(@"%@ and crew: All bad guys killed, here is your father.", self.name);
return 1; // 第二次成功
}
}
- (int)killTheBadGuy { return result; }
- (NSString *)description { return self.name; } // 方便NSLog直接輸出名字
@end
#import <Foundation/Foundation.h>
#import "Girl.h"
#import "Cowboy.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Cowboy *cowboy = [[Cowboy alloc] init];
cowboy.name = @"John Marston";
Girl *girl = [[Girl alloc] initWithName:@"Lucy" WithDelegate:cowboy];
[girl helpHelp]; // 觸發事件
// 運行 RunLoop 6 秒觀察輸出
NSDate *date = [NSDate date];
[[NSRunLoop currentRunLoop] runUntilDate:[date dateByAddingTimeInterval:6]];
}
return 0;
}
Lucy: My name is Lucy, my dad was taken by bad guys, can you save him?
John Marston: OK young lady, wait for good news!
John Marston: Too many of them, I'll gather my men!
Lucy: My heart is broken, you must save him!
John Marston and crew: All bad guys killed, here is your father.
Lucy: Thank you so much, marry me~
| 技術點 | 說明 |
|---|---|
@protocol | 定義介面契約,編譯期檢查一致性 |
id <Protocol> | 聲明符合協議的對象,支持多態 |
assign vs weak | MRC用 assign,ARC用 weak 避免循環引用 |
respondsToSelector: | 運行時檢查對象是否實現方法,防崩潰 |
| 私有方法實現協議 | 在 .m 中實現,.h 不暴露,封裝內部邏輯 |
NSTimer + RunLoop | 模擬異步事件輪詢 |
委托模式實現了「關注點分離」:姑娘只管求救,牛仔只管救人,雙方通過協議鬆耦合。這是 Objective-C / Cocoa 開發的靈魂,掌握它等於掌握了 iOS 開發的核心架構思維。