デリゲートによる通知を送る際は通常1個のクラスしか通知先に指定できませんが、複数のクラスへ同時に通知を送りたい場合があるかと思います。
同時に通知を送るにはNotificationCenterを使う方法もありますが、この手法は通知元から受け取ったデータを通知先で判別するのが困難です。一方、デリゲートは通知先へ渡すデータを直接引数に指定することができます。
そこでデリゲートによって複数のクラスへ同時に通知を送る方法を考えてみました。
初めての投稿で、まだ言語の知識も浅いので大目に見ていただけると幸いです。
#デリゲートモデルの定義
##DelegateCenter
通知先クラスのリストを持ち、実際に通知を送るクラスです。
DelegateCenter.h
#import "DelegateObject.h"
@interface DelegateCenter : NSObject
@property (nonatomic) id delegate;
- (void)doDelegate;
@end
DelegateCenter.m
#import "DelegateCenter.h"
@implementation DelegateCenter
#pragma mark - Setter
- (void)setDelegate:(id)delegate {
// 一般的なデリゲートと同じように通知先を指定できるように、セッタを書き換える
DelegateObject *delegateObject = [DelegateObject new];
delegateObject.delegate = delegate;
if (self.delegate) {
[self.delegate addObject:delegateObject];
} else {
NSMutableArray <DelegateObject *> *mDelegate = [@[delegateObject] mutableCopy];
_delegate = mDelegate;
}
}
#pragma mark - Delegate Trigger
- (void)doDelegate {
if (self.delegate) {
for (DelegateObject *delegateObject in self.delegate) {
if ([delegateObject.delegate respondsToSelector:@selector(delegateCenter:)]) {
[delegateObject.delegate delegateCenter:self];
}
}
}
}
@end
##DelegateObject
デリゲートプロトコルを定義し、個々の通知先クラスを保持するクラスです。
メモリリークを避けるためにweakプロパティで保持しています。
DelegateObject.h
@class DelegateCenter;
@protocol Delegate <NSObject>
- (void)delegateCenter:(DelegateCenter *)delegateCenter;
@end
@interface DelegateObject : NSObject
@property (weak, nonatomic) id <Delegate> delegate;
@end
#デリゲートモデルの使用例
3個のViewControllerをそれぞれデリゲートの通知先に指定し、そのいずれかのクラスから自身を含む全クラスへ通知を送ります。
FirstViewController.m
@interface FirstViewController () <Delegate>
@property (nonatomic) DelegateCenter *delegateCenter;
@end
@implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// デリゲート管理クラスの通知先に自身を登録
self.delegateCenter = [DelegateCenter new];
self.delegateCenter.delegate = self;
}
- (IBAction)tapNext:(UIButton *)sender {
// ボタン押下で次のVCへ遷移
SecondViewController *vc = [SecondViewController new];
// デリゲート管理クラスを共有する
vc.delegateCenter = self.delegateCenter;
[self presentViewController:vc animated:YES completion:nil];
}
- (void)delegateCenter:(DelegateCenter *)delegateCenter {
// 通知を受け取ると呼ばれる
}
- (IBAction)tapDelegate:(UIButton *)sender {
// 通知先に登録されている全クラスへ通知を送る
[self.delegateCenter doDelegate];
}
@end
SecondViewController.h
@interface SecondViewController : UIViewController
@property (nonatomic) DelegateCenter *delegateCenter;
@end
SecondViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// デリゲート管理クラスの通知先に自身を追加
self.delegateCenter.delegate = self;
}
- (IBAction)tapNext:(UIButton *)sender {
// ボタン押下で次のVCへ遷移
ThirdViewController *vc = [ThirdViewController new];
// デリゲート管理クラスを共有する
vc.delegateCenter = self.delegateCenter;
[self presentViewController:vc animated:YES completion:nil];
}
- (void)delegateCenter:(DelegateCenter *)delegateCenter {
// 通知を受け取ると呼ばれる
}
- (IBAction)tapDelegate:(UIButton *)sender {
// 通知先に登録されている全クラスへ通知を送る
[self.delegateCenter doDelegate];
}
@end
ThirdViewController.h
@interface ThirdViewController : UIViewController
@property (nonatomic) DelegateCenter *delegateCenter;
@end
ThirdViewController.m
@implementation ThirdViewController
- (void)viewDidLoad {
[super viewDidLoad];
// デリゲート管理クラスの通知先に自身を追加
self.delegateCenter.delegate = self;
}
- (void)delegateCenter:(DelegateCenter *)delegateCenter {
// 通知を受け取ると呼ばれる
}
- (IBAction)tapDelegate:(UIButton *)sender {
// 通知先に登録されている全クラスへ通知を送る
[self.delegateCenter doDelegate];
}
@end
これで、各クラスのdelegateボタンを押下すると自身を含む複数の通知先に通知を送れるようになります。