To use Strategy Pattern in Objective-C, I think it is mainly by selector.
To omit if...else
, use Objective-C runtime, convert string matching to choose selector (Strategy).
Am my understanding right?
Here is demo: Strategy Pattern in ResponderChain Communication Pattern.
create a Router to use ResponderChain Communication
#import "UIResponder+Router.h"
@implementation UIResponder (Router)
- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo
{
[[self nextResponder] routerEventWithName:eventName userInfo:userInfo];
}
@end
event sender:
[self routerEventWithName:kBLGoodsDetailBottomBarEventTappedBuyButton userInfo:nil];
event receiver:
#pragma mark - event response
- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo
{
/*
do things you want
*/
// call the upper ,by ResponderChain
// [super routerEventWithName:eventName userInfo:userInfo];
}
Here is the Strategy part:
when the event sources are many, use strategy to specify the concrete situation.
#pragma mark - event response
- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo
{
NSInvocation *invocation = self.eventStrategy[eventName];
[invocation setArgument:&userInfo atIndex:2];
[invocation invoke];
// call the upper ,by ResponderChain
// [super routerEventWithName:eventName userInfo:userInfo];
}
- (NSDictionary <NSString *, NSInvocation *> *)eventStrategy
{
if (_eventStrategy == nil) {
_eventStrategy = @{
kBLGoodsDetailTicketEvent:[self createInvocationWithSelector:@selector(ticketEvent:)],
kBLGoodsDetailPromotionEvent:[self createInvocationWithSelector:@selector(promotionEvent:)],
kBLGoodsDetailScoreEvent:[self createInvocationWithSelector:@selector(scoreEvent:)],
kBLGoodsDetailTargetAddressEvent:[self createInvocationWithSelector:@selector(targetAddressEvent:)],
kBLGoodsDetailServiceEvent:[self createInvocationWithSelector:@selector(serviceEvent:)],
kBLGoodsDetailSKUSelectionEvent:[self createInvocationWithSelector:@selector(skuSelectionEvent:)],
};
}
return _eventStrategy;
}
NSInvocation
is for cases with dynamic number and types of arguments; you don't need it if the methods called all have a fixed signature known at compile time -- you can useobjc_msgSend
directly. In fact, since here they are all methods that take one object parameter, you can call it usingperformSelector:withObject:
. Just store the selector as a string in your dictionary, and call it withperformSelector:withObject:
.