| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_COMMAND_DISPATCHER_H_ |
| #define IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_COMMAND_DISPATCHER_H_ |
| |
| #import <Foundation/Foundation.h> |
| |
| // CommandDispatcher allows coordinators to register as command handlers for |
| // specific selectors. Other objects can call these methods on the dispatcher, |
| // which in turn will forward the call to the registered handler. |
| |
| // While CommandDispatcher conforms functionally to any protocols it is |
| // dispatching for, the compiler doesn't (and can't) know that. To call |
| // dispatched methods on a dispatcher, it's best to use a typecast to an |
| // id pointer conforming to the relevant protocols. Such a pointer should also |
| // be passed into objects that need to call, but not configure, the dispatcher |
| // (anything other than a coordinator). To create such a pointer in a way that |
| // both compiles and is checked for correctness at runtime, use the provided |
| // function-like macro HandlerForProtocol, defined below. Usage is as follows: |
| // |
| // id<SomeProtocol> handler = HandlerForProtocol(dispatcher, SomeProtocol); |
| // |
| // `dispatcher` should be a CommandDispatcher object, and SomeProtocol is |
| // the *name* of a protocol (not a string, not a Protocol* pointer, and not |
| // an @protocol() expression to generate one). |
| // |
| // This will typecast `dispatcher` to an id<SomeProtocol> (for compile-time |
| // type checking), and verify that `dispatcher` is currently dispatching |
| // for `protocol` (for run-time verification). If `dispatcher` isn't dispatching |
| // for `protocol`, HandlerForProtocol() returns nil and DCHECKs. |
| // |
| #define HandlerForProtocol(Dispatcher, ProtocolName) \ |
| static_cast<id<ProtocolName>>( \ |
| [Dispatcher strictCallableForProtocol:@protocol(ProtocolName)]) |
| |
| @interface CommandDispatcher : NSObject |
| |
| // Registers the given `target` to receive forwarded messages for the given |
| // `selector`. |
| - (void)startDispatchingToTarget:(id)target forSelector:(SEL)selector; |
| |
| // Removes forwarding registration for the given `selector`. |
| - (void)stopDispatchingForSelector:(SEL)selector; |
| |
| // Registers the given `target` to receive forwarded messages for the methods of |
| // the given `protocol`. Only required instance methods are registered. The |
| // other definitions in the protocol are ignored. |
| - (void)startDispatchingToTarget:(id)target forProtocol:(Protocol*)protocol; |
| |
| // Removes forwarding registration for the given `selector`. Only dispatching to |
| // required instance methods is removed. The other definitions in the protocol |
| // are ignored. |
| - (void)stopDispatchingForProtocol:(Protocol*)protocol; |
| |
| // Removes all forwarding registrations for the given `target`. |
| - (void)stopDispatchingToTarget:(id)target; |
| |
| // YES if the dispatcher is currently dispatching for `protocol`, including |
| // (recursively) any protocols that `protocol` conforms to. |
| - (BOOL)dispatchingForProtocol:(Protocol*)protocol; |
| |
| // Returns the receiver if it is dispatching for `protocol`, and CHECK()s |
| // otherwise. |
| - (CommandDispatcher*)strictCallableForProtocol:(Protocol*)protocol; |
| |
| // After this method is called, -stopDispatching methods will stop dispatching, |
| // but this object will continue to respond to registered selectors by silently |
| // failing. This method should be called on -applicationWillTerminate. It helps |
| // avoid untangling the dispatcher chains in the correct order, which sometimes |
| // can be very hard. |
| - (void)prepareForShutdown; |
| |
| @end |
| |
| #endif // IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_COMMAND_DISPATCHER_H_ |