在 iOS 中使用 NSNotificationCenter 進行跨組件通信時,正確傳遞自定義對象(如 MyAccount)需要遵循標準流程:註冊觀察者、發送通知、接收處理。
// 全局常量文件或相關類別中
static NSString *const kDidLoginNotification = @"com.myapp.didLogin";
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleLoginNotification:)
name:kDidLoginNotification
object:nil];
}
- (void)dealloc {
// 關鍵:移除觀察者防止崩潰與記憶體洩漏
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)handleLoginNotification:(NSNotification *)notification {
// 從 notification.object 獲取傳遞的對象
MyAccount *account = (MyAccount *)notification.object;
// 也可從 userInfo 獲取字典數據
// NSDictionary *userInfo = notification.userInfo;
if (account) {
// 更新 UI、儲存數據等
NSLog(@"用戶登入:%@", account.username);
}
}
- (void)loginSuccessWithAccount:(MyAccount *)account {
// 業務邏輯...
// 發送通知,將 account 作為 object 傳遞
[[NSNotificationCenter defaultCenter] postNotificationName:kDidLoginNotification
object:account
userInfo:nil];
}
註冊時的 name 與發送時的 postNotificationName: 必須是同一個字串對象,建議使用常量定義。
Selector 對應的方法必須接受單一 NSNotification * 參數:
// 正確
- (void)handleNotification:(NSNotification *)notification;
// 錯誤:無法直接接收自定義對象
- (void)handleNotification:(MyAccount *)account; // 不會被調用
- (void)handleLoginNotification:(NSNotification *)notification {
dispatch_async(dispatch_get_main_queue(), ^{
MyAccount *account = (MyAccount *)notification.object;
// 更新 UI
});
}
notification.object 不會自動 retain,若需持有請自行 retain/copydealloc 或 viewDidDisappear 中移除觀察者id observer = [[NSNotificationCenter defaultCenter]
addObserverForName:kDidLoginNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
MyAccount *account = (MyAccount *)note.object;
// 自動在主隊列執行,適合 UI 更新
}];
// 移除時需保存 observer 令牌
[[NSNotificationCenter defaultCenter] removeObserver:observer];
| 方案 | 適用場景 | 耦合度 |
|---|---|---|
| NotificationCenter | 多對多、跨模組、無直接引用 | 低 |
| Delegate 代理 | 一對一、明確所有權關係 | 中 |
| Block/Closure 回調 | 簡單異步回調 | 低 |
| KVO | 屬性變化觀察 | 中 |