「Objective-Cでのイベント処理」、イベントの委任(たとえば、 viewWillAppear:(BOOL)animated )、プログラムのさまざまな場所で同時に聴く必要がある場合の不便さについて、多くのコピーが既に壊れています。
Observerテンプレートの実装を提供したいと思います。これは、C ++ 0xの能力を使用し、次のように、厳密に型指定されたパラメーターのリストを使用して信号を宣言できます。
new TLSignal<NSString *, BOOL>(self);
なぜなら 私のC ++に関する知識はかなり乏しいため、このコードを改善するためのアドバイスに感謝します。
猫の下で興味を持ってください。
問題の本質
多くの場合、イベントについて他のオブジェクトに通知する必要がある場合があります(プロパティの変更、状態の変更など)。一方、複数のリスナーが同時にイベントを受信できるように、1対多の対応を監視できる必要があります。 このため、デリゲート付きのオプションはすぐに消えます。
組み込みのObjective-Cツールにはどのようなオプションがありますか?
- 通知センター -もちろん、NCには独自の適用分野がありますが、プログラム全体のグローバルイベントにより適しています。イベントは文字列識別子によって識別されますが、これは良くありません。 さて、そのようなソリューションのパフォーマンスは、APIと同様に貧弱です。
- Key-Value Observing(KVO)は、オブジェクトのプロパティが変更されたときのイベントの特殊なケースです。 Bindingsのような素晴らしいことを実行できますが、APIはその魅力をすべて無効にします。
オブザーバーパターン
Wikipediaの記事よりも詳しく説明できないと思うので、詳細のみを明確にします。
- イベントのリスナーは、通常のObjective-Cブロックになります。
- 私のシグナルの助けを借りてイベントを送信するオブジェクトは、イベントの作成と破壊を担当します。
- 通知中に実行されるメソッドのパラメーターのタイプと数は、C ++テンプレートを介して設定され、コンパイル段階でチェックされます。
したがって、シグナル宣言は次のようになります。
new TLSignal<NSString *, BOOL>(self);
つまり:
- 文字列(NSString)とブール値(BOOL)の2つのパラメーターを取る信号を作成しました
- シグナルのターゲットはself、つまり この信号が作成されるオブジェクト。
この場合、このイベントをリッスンするブロックは次のようになります。
auto observerBlock = ^(id target, NSString *stringParam, BOOL boolParam) { NSLog(@"%@ %@ %d", target, stringParam, boolParam); };
最初のパラメーターIDターゲットに注意してください。これは常に送信され、この信号の「ホルダー」に等しくなります。
使用例
使用例のないコードはコードではないので、プログラムの小さな例を挙げたいと思います。その例では、信号の利点とその使用方法を示したいと思います。
ExampleViewController.h
#import <UIKit/UIKit.h> #import "Signals.h" @interface ExampleViewController : UIViewController @property (nonatomic, readonly) TLSignal<UIView *> *viewDidLoadSignal; @end
ここではすべてが簡単です。識別子viewDidLoadSignalを使用してシグナルを宣言します。これにより、UIViewインスタンスがリスナーに渡されます。
ExampleViewController.mm
#import "ExampleViewController.h" @implementation ExampleViewController @synthesize viewDidLoadSignal = _viewDidLoadSignal; -(TLSignal<UIView *> *)viewDidLoadSignal { if(!_viewDidLoadSignal) { // ( ) _viewDidLoadSignal = new TLSignal<UIView *>(self); } return _viewDidLoadSignal; } -(void)viewDidLoad { [super viewDidLoad]; // , UIView self.viewDidLoadSignal->notify(self.view); } @end
Appdelegate.mm
#import "AppDelegate.h" #import "ExampleViewController.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)options { UIWindow window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.viewController = [[ExampleViewController alloc] initWithNibName:@"ViewController" bundle:nil]; // , UIView self.viewController.viewDidLoadSignal->addObserver(^(TLSignal<UIView *> *signal, UIView *targetView) { targetView.backgroundColor = [UIColor blackColor]; }); self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES; } @end
信号が使用されるコードのファイル拡張子は、.mではなく.mmでなければならないことに注意してください。そうしないと、通常のObjective-Cコードとして認識され、プラスの魔法を理解できません。
おわりに
Objective-C(たとえば2.5または3.0)で類似したものが標準レベルで表示されることを心から願っています。これが起こるまで、ライブラリを使用することをお勧めします(非常に使いやすく、小さなコードでも明確です私が持っているC ++の知識:)):
GitHubのTLSignals
先日、Cocoapodsに表示されます。これが発生するまで、 TLSignals.hファイルをプロジェクトにコピーして、作業を開始できます。
コードはテストで部分的にカバーされています。テストを読むと、その仕組みをよりよく理解できます。
GitHubのTLSignalsTests.mm
追加と改善に感謝するだけでなく、C ++の側面から弱点で鼻を突くだけでなく、一般的には、私たち全員が学んでいるだけなので;)
誤字や文法上の誤りが見つかった場合は、コメントが乱雑にならないように、それらについて個人的なメッセージに書いてください。
ご清聴ありがとうございました!
関連リンク
- github.com/bsideup/TLSignals-ライブラリ自体(呼び出し可能な場合)。
- en.wikipedia.org/wiki/Observer_pattern-オブザーバーパターンの説明。
- en.wikipedia.org/wiki/Variadic_Templates-可変長テンプレート。 これがなければ、信号のタイプに応じて異なる数の引数を作成することはできません。
- habrahabr.ru/post/101430-それらについてですが、ネイティブHabrの形式です。