📜 ⬆️ ⬇️

Observer Pattern with strong typing or why do we need Objective-C ++



Already many copies were broken about the topic “event handling in Objective-C”, about delegating events (for example, viewWillAppear: (BOOL) animated ), about how it is not convenient when you need to listen to them simultaneously in different places of the program.

I want to offer you my implementation of the Observer template, which uses the power of C ++ 0x and allows you to declare signals with a hard-typed list of parameters, for example, like this:
new TLSignal<NSString *, BOOL>(self); 

Since Since my knowledge of C ++ is pretty scanty, I would be grateful for any advice on how to improve this code.
')
Interested please under the cat.

The essence of the problem


There are often situations when it is necessary to notify other objects about any event (property changed, state change, etc.), and you must be able to comply with the “One-to-many” correspondence so that several listeners can simultaneously receive the event. For this reason, the option with delegates immediately disappears.
What options do Objective-C's built-in tools offer us?
  1. Notification Center - certainly, NC has its own field of application, but it is more suitable for global events within the entire program, just as the identification of events follows a string identifier, which is not good. Well, the performance of this solution leaves much to be desired, as well as the API.
  2. Key-Value Observing (KVO) is a special case of an event when some property of an object changes. It allows you to do wonderful things like Bindings, but the API reduces all its charms to nothing.


Observer pattern


Better than an article on Wikipedia, I think it’s impossible to tell me, so I’ll just clarify the details:



So, the signal declaration looks like this:
  new TLSignal<NSString *, BOOL>(self); 

Which means that:


In this case, the block listening to this event will look like this:
 auto observerBlock = ^(id target, NSString *stringParam, BOOL boolParam) { NSLog(@"%@ %@ %d", target, stringParam, boolParam); }; 

Pay attention to the 1st parameter id target, it is always transmitted and is equal to the “holder” of this signal.

Usage example


A code without an example of use is not a code, so I want to give a small example of a program, by the example of which I would like to demonstrate what the actual advantage of signals is and how they can be used.

ExampleViewController.h

 #import <UIKit/UIKit.h> #import "Signals.h" @interface ExampleViewController : UIViewController @property (nonatomic, readonly) TLSignal<UIView *> *viewDidLoadSignal; @end 

Everything is simple here, we declare a signal with the viewDidLoadSignal identifier, which will transmit the UIView instance to the listeners.

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 


Please note that the extension of files with code that uses signals must be .mm and not .m, otherwise it will be perceived as ordinary Objective-C code and will not understand our plus magic!

Conclusion


I sincerely hope that something like this at the standard level will appear in Objective-C (for example, 2.5 or 3.0), but for now this has not happened, I suggest you use my library (it is extremely easy to use, the code is also understandable even with small knowledge in C ++, with which I have :)):
TLSignals on github

The other day it will appear in Cocoapods, but until this happens, you can simply copy the TLSignals.h file to your project and start working with it.

The code is partially covered with tests whose reading will help you better understand how it works:
TLSignalsTests.mm on GitHub

I would be grateful for additions and improvements, as well as poking my nose at weak moments on the part of C ++ and in general, because we are all just learning;)

If you find typos or grammatical errors, please write about them with a personal message, so as not to clog these comments.

Thanks for attention!

Related Links


Source: https://habr.com/ru/post/162235/


All Articles