Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// Since ModelManager is usually a simple facade for many other smaller managers, it can dispatch most method calls to its subcomponents based on which protocol includes the selector.
BOOL ProtocolIncludesSelector (Protocol *protocol, SEL selector)
{
struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES);
return NULL != methodDescription.name;
}
@implementation ModelManager
...
- (instancetype)init
{
self = [super init];
if (self) {
self.dataManager = [[DataManager alloc] initWithUpdatePropagator:self];
self.remoteConnectionManager = [[RemoteConnectionManager alloc] initWithDataManager:self.dataManager];
}
return self;
}
- (id)forwardingTargetForSelector:(SEL)selector
{
if (ProtocolIncludesSelector(@protocol(DataManagerOperations), selector)) {
return self.dataManager;
} else if (ProtocolIncludesSelector(@protocol(RemoteConnectionManagerOperations), selector)) {
return self.remoteConnectionManager;
} else if (...) {
...
} else {
return nil;
}
}
...
@end
// The submanagers can then answer any concrete data access requests.
@protocol DataManagerOperations <NSObject>
- (UIImage *)avatarImageForEmailAddress:(NSString *)emailAddress;
...
@end
@protocol RemoteConnectionManagerOperations <NSObject>
- (void)requestAvatarImageForEmailAddress:(NSString *)emailAddress;
...
@end
@implementation DataManager
...
- (void)saveAvatarImage:(UIImage *)image forEmailAddress:(NSString *)emailAddress
{
self.avatarImagesForEmailAddresses[emailAddress] = image;
[self.updatePropagator propagateUpdate:[ModelUpdate avatarImageUpdateForEmailAddress:emailAddress]];
}
- (UIImage *)avatarImageForEmailAddress:(NSString *)emailAddress
{
return self.avatarImagesForEmailAddresses[emailAddress];
}
...
@end
@implementation RemoteConnectionManager
...
- (void)requestAvatarImageForEmailAddress:(NSString *)emailAddress
{
if ([self.dataManager hasAvatarImageForEmailAddress:emailAddress]) {
return;
}
[self sendRemoteAvatarImageRequestForEmailAddress:emailAddress withCompletionBlock:^(UIImage *image) {
[self.dataManager saveAvatarImage:image forEmailAddress:emailAddress];
}];
}
...
@end
@implementation SomeViewController
...
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupAvatarView];
[[ModelManager sharedInstance] requestAvatarImageForEmailAddress:self.emailAddress];
}
- (void)modelUpdated:(ModelUpdate *)update
{
if (update.type == ModelUpdateTypeAvatarImage && [update.emailAddres isEqualToString:self.emailAddress]) {
[self setupAvatarView];
}
}
- (void)setupAvatarView
{
self.avatarView.image = [[ModelManager sharedInstance] avatarImageForEmailAddress:self.emailAddress];
}
...
@end
// These examples are very simplified, but hopefully enough to clarify the whole concept.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment