Created
July 27, 2013 05:59
-
-
Save beccadax/6093944 to your computer and use it in GitHub Desktop.
NSApplication subclass with additional delegate methods for various useful things.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GSTApplication.h | |
// Ingist | |
// | |
// Created by Brent Royal-Gordon on 7/12/13. | |
// Copyright (c) 2013 Architechies. All rights reserved. | |
// | |
#import <Cocoa/Cocoa.h> | |
#import "GSTServicesProvider.h" | |
@protocol GSTApplicationDelegate; | |
@interface GSTApplication : NSApplication | |
@property (strong) id <GSTApplicationDelegate> delegate; | |
@end | |
@protocol GSTApplicationDelegate <NSApplicationDelegate> | |
@optional | |
- (void)gst_application:(GSTApplication *)app openURL:(NSURL*)URL; | |
- (GSTServiceHandler)gst_application:(GSTApplication *)app handlerForServiceNamed:(NSString*)name; | |
- (void)gst_applicationShowHelp:(GSTApplication *)app; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GSTApplication.m | |
// Ingist | |
// | |
// Created by Brent Royal-Gordon on 7/12/13. | |
// Copyright (c) 2013 Architechies. All rights reserved. | |
// | |
#import "GSTApplication.h" | |
@interface GSTApplication () <GSTServicesProviderDelegate> | |
@end | |
@implementation GSTApplication | |
@dynamic delegate; | |
- (void)didReceiveGetURLEvent:(NSAppleEventDescriptor*)URLEvent replyEvent:(NSAppleEventDescriptor*)replyEvent { | |
NSString * URLString = [[URLEvent paramDescriptorForKeyword:keyDirectObject] stringValue]; | |
NSURL * URL = [NSURL URLWithString:URLString]; | |
if([self.delegate respondsToSelector:@selector(gst_application:openURL:)]) { | |
[self.delegate gst_application:self openURL:URL]; | |
} | |
} | |
- (void)finishLaunching { | |
[NSAppleEventManager.sharedAppleEventManager setEventHandler:self andSelector:@selector(didReceiveGetURLEvent:replyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; | |
GSTServicesProvider.sharedServicesProvider.delegate = self; | |
self.servicesProvider = GSTServicesProvider.sharedServicesProvider; | |
[super finishLaunching]; | |
} | |
- (GSTServiceHandler)servicesProvider:(GSTServicesProvider *)serviceProvider handlerForServiceNamed:(NSString *)name { | |
if(![self.delegate respondsToSelector:@selector(gst_application:handlerForServiceNamed:)]) { | |
return nil; | |
} | |
return [self.delegate gst_application:self handlerForServiceNamed:name]; | |
} | |
- (void)showHelp:(id)sender { | |
if([self.delegate respondsToSelector:@selector(gst_applicationShowHelp:)]) { | |
[self.delegate gst_applicationShowHelp:self]; | |
return; | |
} | |
[super showHelp:sender]; | |
} | |
@end | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GSTServiceProvider.h | |
// Ingist | |
// | |
// Created by Brent Royal-Gordon on 7/25/13. | |
// Copyright (c) 2013 Architechies. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
typedef void (^GSTServiceHandler)(NSPasteboard * pboard, NSString * userData, NSError ** error); | |
@protocol GSTServicesProviderDelegate; | |
@interface GSTServicesProvider : NSObject | |
@property (weak) id <GSTServicesProviderDelegate> delegate; | |
+ (instancetype)sharedServicesProvider; | |
@end | |
@protocol GSTServicesProviderDelegate <NSObject> | |
- (GSTServiceHandler)servicesProvider:(GSTServicesProvider*)serviceProvider handlerForServiceNamed:(NSString*)name; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GSTServiceProvider.m | |
// Ingist | |
// | |
// Created by Brent Royal-Gordon on 7/25/13. | |
// Copyright (c) 2013 Architechies. All rights reserved. | |
// | |
#import "GSTServicesProvider.h" | |
#import <objc/runtime.h> | |
@interface GSTServicesProvider () | |
@property (strong, nonatomic) NSMutableDictionary * serviceHandlers; | |
@end | |
@implementation GSTServicesProvider | |
+ (NSString *)serviceNameForSelector:(SEL)aSelector { | |
NSString * selectorName = NSStringFromSelector(aSelector); | |
NSRange range = [selectorName rangeOfString:@":userData:error:" options:NSAnchoredSearch|NSBackwardsSearch]; | |
if(range.location == NSNotFound) { | |
return nil; | |
} | |
return [selectorName substringToIndex:range.location]; | |
} | |
- (GSTServiceHandler)handlerForServiceNamed:(NSString*)name { | |
GSTServiceHandler handler = self.serviceHandlers[name]; | |
if(!handler) { | |
handler = [[self.delegate servicesProvider:self handlerForServiceNamed:name] copy]; | |
self.serviceHandlers[name] = handler; | |
} | |
return handler; | |
} | |
+ (BOOL)resolveInstanceMethod:(SEL)sel { | |
NSString * serviceName = [self.class serviceNameForSelector:sel]; | |
if(!serviceName) { | |
return [super resolveInstanceMethod:sel]; | |
} | |
IMP imp = imp_implementationWithBlock(^(GSTServicesProvider * self, NSPasteboard * pboard, NSString * userData, NSError ** error) { | |
GSTServiceHandler handler = [self handlerForServiceNamed:serviceName]; | |
if(!handler) { | |
[self doesNotRecognizeSelector:sel]; | |
return; | |
} | |
handler(pboard, userData, error); | |
}); | |
NSString * str = [NSString stringWithFormat:@"%s%s%s%s%s%s", @encode(void), @encode(id), @encode(SEL), @encode(id), @encode(id), @encode(__autoreleasing id *)]; | |
class_addMethod(self, sel, imp, str.UTF8String); | |
return YES; | |
} | |
- (BOOL)respondsToSelector:(SEL)aSelector { | |
NSString * serviceName = [self.class serviceNameForSelector:aSelector]; | |
if(serviceName && ![self handlerForServiceNamed:serviceName]) { | |
return NO; | |
} | |
return [super respondsToSelector:aSelector]; | |
} | |
- (id)initSingleton { | |
if((self = [super init])) { | |
_serviceHandlers = [NSMutableDictionary new]; | |
} | |
return self; | |
} | |
+ (id)allocWithZone:(NSZone *)zone { | |
static GSTServicesProvider * singleton; | |
static dispatch_once_t once; | |
dispatch_once(&once, ^{ | |
singleton = [[super allocWithZone:zone] initSingleton]; | |
}); | |
return singleton; | |
} | |
- (id)init { | |
return self; | |
} | |
+ (instancetype)sharedServicesProvider { | |
return [self new]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@brentdax
Hi!
Could you explain is this example about
.servicesProvider
property ofNSApplication
?I still can't figure out how to implement "servicesProvider" method. See
As I understand,
ServicesProvider
uses dynamic dispatching by filtering methods with 3 parameters ( pasteboard, userData and error ).Is it correct?
Thanks!
P.S. It would be nice if you replied with simple ServicesProvider which do nothing but print to console its parameters.