Skip to content

Commit

Permalink
Refactored NSUIApplication+MIKMIDI to move most code into a separate …
Browse files Browse the repository at this point in the history
…MIKMIDIResponderHierarchyManager class.
  • Loading branch information
Andrew Madsen committed May 7, 2015
1 parent 8c41a7b commit 3351a6a
Showing 1 changed file with 136 additions and 66 deletions.
202 changes: 136 additions & 66 deletions Source/NSUIApplication+MIKMIDI.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import "NSUIApplication+MIKMIDI.h"
#import "MIKMIDIResponder.h"
#import "MIKMIDICommand.h"
#import <objc/runtime.h>

#if !__has_feature(objc_arc)
#error NSApplication+MIKMIDI.m must be compiled with ARC. Either turn on ARC for the project or set the -fobjc-arc flag for NSApplication+MIKMIDI.m in the Build Phases for this target
Expand Down Expand Up @@ -41,69 +42,53 @@ static BOOL MIKObjectRespondsToMIDICommand(id object, MIKMIDICommand *command)
return [object conformsToProtocol:@protocol(MIKMIDIResponder)] && [(id<MIKMIDIResponder>)object respondsToMIDICommand:command];
}

@implementation MIK_APPLICATION_CLASS (MIKMIDI)
@interface MIKMIDIResponderHierarchyManager : NSObject

@property (nonatomic, strong) NSHashTable *registeredMIKMIDIResponders;
@property (nonatomic, strong) NSSet *registeredMIKMIDIRespondersAndSubresponders;

@property (nonatomic, strong, readonly) NSSet *allMIDIResponders;

@end

+ (NSHashTable *)registeredMIKMIDIResponders
@implementation MIKMIDIResponderHierarchyManager

+ (NSPointerFunctionsOptions)hashTableOptions
{
static NSHashTable *registeredMIKMIDIResponders = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{

#if TARGET_OS_IPHONE
NSPointerFunctionsOptions options = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
return NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
#elif (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_7)
NSPointerFunctionsOptions options = NSPointerFunctionsZeroingWeakMemory | NSPointerFunctionsObjectPersonality;
return NSPointerFunctionsZeroingWeakMemory | NSPointerFunctionsObjectPersonality;
#else
NSPointerFunctionsOptions options = NSHashTableWeakMemory | NSPointerFunctionsObjectPersonality;
return NSHashTableWeakMemory | NSPointerFunctionsObjectPersonality;
#endif
registeredMIKMIDIResponders = [[NSHashTable alloc] initWithOptions:options capacity:0];
});
return registeredMIKMIDIResponders;
}

- (void)registerMIDIResponder:(id<MIKMIDIResponder>)responder;
- (instancetype)init
{
[[[self class] registeredMIKMIDIResponders] addObject:responder];
self = [super init];
if (self) {
NSPointerFunctionsOptions options = [[self class] hashTableOptions];
_registeredMIKMIDIResponders = [[NSHashTable alloc] initWithOptions:options capacity:0];
}
return self;
}

- (void)unregisterMIDIResponder:(id<MIKMIDIResponder>)responder;
- (void)registerMIDIResponder:(id<MIKMIDIResponder>)responder;
{
[[[self class] registeredMIKMIDIResponders] removeObject:responder];
[self.registeredMIKMIDIResponders addObject:responder];
}

- (BOOL)respondsToMIDICommand:(MIKMIDICommand *)command;
- (void)unregisterMIDIResponder:(id<MIKMIDIResponder>)responder;
{
NSSet *registeredResponders = [self respondersForCommand:command inResponders:[self registeredMIDIRespondersIncludingSubresponders]];
if ([registeredResponders count]) return YES;

#if MIKMIDI_SEARCH_VIEW_HIERARCHY_FOR_RESPONDERS
NSSet *viewHierarchyResponders = [self respondersForCommand:command inResponders:[self registeredMIDIRespondersIncludingSubresponders]];
return ([viewHierarchyResponders count] != 0);
#endif
return NO;
[self.registeredMIKMIDIResponders addObject:responder];
}

- (void)handleMIDICommand:(MIKMIDICommand *)command;
{
NSSet *registeredResponders = [self respondersForCommand:command inResponders:[self registeredMIDIRespondersIncludingSubresponders]];
for (id<MIKMIDIResponder> responder in registeredResponders) {
[responder handleMIDICommand:command];
}

#if MIKMIDI_SEARCH_VIEW_HIERARCHY_FOR_RESPONDERS
NSMutableSet *viewHierarchyResponders = [[self respondersForCommand:command inResponders:[self MIDIRespondersInViewHierarchy]] mutableCopy];
[viewHierarchyResponders minusSet:registeredResponders];

for (id<MIKMIDIResponder> responder in viewHierarchyResponders) {
NSLog(@"WARNING: Found responder %@ for command %@ by traversing view hierarchy. This path for finding MIDI responders is deprecated. Responders should be explicitly registered with NS/UIApplication.", responder, command);
[responder handleMIDICommand:command];
}
#endif
}
#pragma mark - Public

- (id<MIKMIDIResponder>)MIDIResponderWithIdentifier:(NSString *)identifier;
- (id<MIKMIDIResponder>)MIDIResponderWithIdentifier:(NSString *)identifier
{
NSSet *registeredResponders = [self registeredMIDIRespondersIncludingSubresponders];
NSSet *registeredResponders = self.registeredMIKMIDIRespondersAndSubresponders;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"MIDIIdentifier LIKE %@", identifier];
NSSet *results = [registeredResponders filteredSetUsingPredicate:predicate];
id<MIKMIDIResponder> result = [results anyObject];
Expand All @@ -112,8 +97,7 @@ - (void)handleMIDICommand:(MIKMIDICommand *)command;
if (!result) {
NSMutableSet *viewHierarchyResponders = [[self MIDIRespondersInViewHierarchy] mutableCopy];
[viewHierarchyResponders minusSet:registeredResponders];
results = [viewHierarchyResponders filteredSetUsingPredicate:predicate];

result = [[viewHierarchyResponders filteredSetUsingPredicate:predicate] anyObject];

if (result) {
NSLog(@"WARNING: Found responder %@ for identifier %@ by traversing view hierarchy. This path for finding MIDI responders is deprecated. Responders should be explicitly registered with NS/UIApplication.", result, identifier);
Expand All @@ -123,31 +107,52 @@ - (void)handleMIDICommand:(MIKMIDICommand *)command;
return result;
}

- (NSSet *)allMIDIResponders
#pragma mark - Private

- (NSSet *)recursiveSubrespondersOfMIDIResponder:(id<MIKMIDIResponder>)responder
{
NSMutableSet *result = [[self registeredMIDIRespondersIncludingSubresponders] mutableCopy];
#if MIKMIDI_SEARCH_VIEW_HIERARCHY_FOR_RESPONDERS
[result unionSet:[self MIDIRespondersInViewHierarchy]];
#endif
NSMutableSet *result = [NSMutableSet setWithObject:responder];
if (![responder respondsToSelector:@selector(subresponders)]) return result;

NSArray *subresponders = [responder subresponders];
[result addObjectsFromArray:subresponders];
for (id<MIKMIDIResponder>subresponder in subresponders) {
[result unionSet:[self recursiveSubrespondersOfMIDIResponder:subresponder]];
}

return result;
}

- (NSSet *)registeredMIDIRespondersIncludingSubresponders
#pragma mark - Properties

- (NSSet *)registeredMIKMIDIRespondersAndSubresponders
{
NSMutableSet *result = [NSMutableSet set];
for (id<MIKMIDIResponder> responder in [[self class] registeredMIKMIDIResponders]) {
for (id<MIKMIDIResponder> responder in self.registeredMIKMIDIResponders) {
[result unionSet:[self recursiveSubrespondersOfMIDIResponder:responder]];
}
return result;

#if MIKMIDI_SEARCH_VIEW_HIERARCHY_FOR_RESPONDERS
[result unionSet:[self MIDIRespondersInViewHierarchy]];
#endif

return [result copy];
}

- (NSSet *)allMIDIResponders
{
return self.registeredMIKMIDIRespondersAndSubresponders;
}

#pragma mark - Deprecated

#if MIKMIDI_SEARCH_VIEW_HIERARCHY_FOR_RESPONDERS
- (NSSet *)MIDIRespondersInViewHierarchy
{
NSMutableSet *result = [NSMutableSet set];

// Go through the entire view hierarchy
for (MIK_WINDOW_CLASS *window in [self windows]) {
for (MIK_WINDOW_CLASS *window in [[MIK_APPLICATION_CLASS sharedApplication] windows]) {
if ([window conformsToProtocol:@protocol(MIKMIDIResponder)]) {
[result unionSet:[self recursiveSubrespondersOfMIDIResponder:(id<MIKMIDIResponder>)window]];
}
Expand All @@ -172,7 +177,76 @@ - (NSSet *)MIDIRespondersInViewHierarchy
return result;
}

#endif // MIKMIDI_SEARCH_VIEW_HIERARCHY_FOR_RESPONDERS

@end

#pragma mark -

@implementation MIK_APPLICATION_CLASS (MIKMIDI)

+ (MIKMIDIResponderHierarchyManager *)mik_MIDIResponderHierarchyManager
{
static MIKMIDIResponderHierarchyManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[MIKMIDIResponderHierarchyManager alloc] init];
});
return manager;
}

- (void)registerMIDIResponder:(id<MIKMIDIResponder>)responder;
{
[[[self class] mik_MIDIResponderHierarchyManager] registerMIDIResponder:responder];
}

- (void)unregisterMIDIResponder:(id<MIKMIDIResponder>)responder;
{
[[[self class] mik_MIDIResponderHierarchyManager] unregisterMIDIResponder:responder];
}

- (BOOL)respondsToMIDICommand:(MIKMIDICommand *)command;
{
MIKMIDIResponderHierarchyManager *manager = [[self class] mik_MIDIResponderHierarchyManager];

NSSet *registeredResponders = [self respondersForCommand:command inResponders:manager.allMIDIResponders];
if ([registeredResponders count]) return YES;

#if MIKMIDI_SEARCH_VIEW_HIERARCHY_FOR_RESPONDERS
NSSet *viewHierarchyResponders = [self respondersForCommand:command inResponders:[self MIDIRespondersInViewHierarchy]];
return ([viewHierarchyResponders count] != 0);
#endif
return NO;
}

- (void)handleMIDICommand:(MIKMIDICommand *)command;
{
MIKMIDIResponderHierarchyManager *manager = [[self class] mik_MIDIResponderHierarchyManager];
NSSet *registeredResponders = [self respondersForCommand:command inResponders:manager.allMIDIResponders];
for (id<MIKMIDIResponder> responder in registeredResponders) {
[responder handleMIDICommand:command];
}

#if MIKMIDI_SEARCH_VIEW_HIERARCHY_FOR_RESPONDERS
NSMutableSet *viewHierarchyResponders = [[self respondersForCommand:command inResponders:[self MIDIRespondersInViewHierarchy]] mutableCopy];
[viewHierarchyResponders minusSet:registeredResponders];

for (id<MIKMIDIResponder> responder in viewHierarchyResponders) {
NSLog(@"WARNING: Found responder %@ for command %@ by traversing view hierarchy. This path for finding MIDI responders is deprecated. Responders should be explicitly registered with NS/UIApplication.", responder, command);
[responder handleMIDICommand:command];
}
#endif
}

- (id<MIKMIDIResponder>)MIDIResponderWithIdentifier:(NSString *)identifier;
{
return [[[self class] mik_MIDIResponderHierarchyManager] MIDIResponderWithIdentifier:identifier];
}

- (NSSet *)allMIDIResponders
{
return [[[self class] mik_MIDIResponderHierarchyManager] allMIDIResponders];
}

#pragma mark - Private

Expand All @@ -183,18 +257,14 @@ - (NSSet *)respondersForCommand:(MIKMIDICommand *)command inResponders:(NSSet *)
}]];
}

- (NSSet *)recursiveSubrespondersOfMIDIResponder:(id<MIKMIDIResponder>)responder
#pragma mark - Deprecated

#if MIKMIDI_SEARCH_VIEW_HIERARCHY_FOR_RESPONDERS
- (NSSet *)MIDIRespondersInViewHierarchy
{
NSMutableSet *result = [NSMutableSet setWithObject:responder];
if (![responder respondsToSelector:@selector(subresponders)]) return result;

NSArray *subresponders = [responder subresponders];
[result addObjectsFromArray:subresponders];
for (id<MIKMIDIResponder>subresponder in subresponders) {
[result unionSet:[self recursiveSubrespondersOfMIDIResponder:subresponder]];
}

return result;
return [[[self class] mik_MIDIResponderHierarchyManager] MIDIRespondersInViewHierarchy];
}

#endif // MIKMIDI_SEARCH_VIEW_HIERARCHY_FOR_RESPONDERS

@end

0 comments on commit 3351a6a

Please sign in to comment.