|
28 | 28 | // |
29 | 29 | // More info at <https://github.com/sequelpro/sequelpro> |
30 | 30 |
|
| 31 | +#import <objc/runtime.h> |
| 32 | +static NSMutableDictionary *gScrollViewListeners; |
| 33 | + |
31 | 34 | @implementation NSObject (SPObjectAdditions) |
32 | 35 |
|
33 | 36 | /** |
@@ -92,7 +95,53 @@ - (void)_scrollViewDidChangeBounds:(id)obj |
92 | 95 |
|
93 | 96 | [msg appendFormat:@"self: %p (class <%@>)\n\n",self,[self className]]; |
94 | 97 |
|
| 98 | + NSString *key = [NSString stringWithFormat:@"snd=%p,obs=%p",obj,self]; |
| 99 | + |
| 100 | + [msg appendFormat:@"registration info for pair (%@):\n %@",key,[gScrollViewListeners objectForKey:key]]; |
| 101 | + |
95 | 102 | @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:msg userInfo:nil]; |
96 | 103 | } |
97 | 104 |
|
98 | 105 | @end |
| 106 | + |
| 107 | + |
| 108 | +@implementation NSNotificationCenter (SPScrollViewDebug) |
| 109 | + |
| 110 | ++ (void)load |
| 111 | +{ |
| 112 | + static dispatch_once_t onceToken; |
| 113 | + |
| 114 | + dispatch_once(&onceToken, ^{ |
| 115 | + gScrollViewListeners = [[NSMutableDictionary alloc] init]; |
| 116 | + |
| 117 | + Class notificationCenter = [self class]; |
| 118 | + |
| 119 | + SEL orig = @selector(addObserver:selector:name:object:); |
| 120 | + SEL exch = @selector(sp_addObserver:selector:name:object:); |
| 121 | + |
| 122 | + Method origM = class_getInstanceMethod(notificationCenter, orig); |
| 123 | + Method exchM = class_getInstanceMethod(notificationCenter, exch); |
| 124 | + |
| 125 | + method_exchangeImplementations(origM, exchM); |
| 126 | + }); |
| 127 | + |
| 128 | +} |
| 129 | + |
| 130 | +- (void)sp_addObserver:(id)notificationObserver selector:(SEL)notificationSelector name:(NSString *)notificationName object:(id)notificationSender |
| 131 | +{ |
| 132 | + if(notificationSelector == @selector(_scrollViewDidChangeBounds:) && [notificationName isEqualToString:NSViewBoundsDidChangeNotification]) { |
| 133 | + NSString *key = [NSString stringWithFormat:@"snd=%p,obs=%p",notificationSender,notificationObserver]; |
| 134 | + NSMutableString *val = [NSMutableString string]; |
| 135 | + [val appendFormat:@"observer: %1$p (class %2$@) description: %1$@\n",notificationObserver,[notificationObserver className]]; |
| 136 | + if([notificationObserver isKindOfClass:[NSView class]]) { |
| 137 | + [val appendFormat:@" view info: id=%@, tag=%ld\n",[(NSView *)notificationObserver identifier], [(NSView *)notificationObserver tag]]; |
| 138 | + } |
| 139 | + [val appendFormat:@"\nbacktrace:\n%@\n\n",[NSThread callStackSymbols]]; |
| 140 | + |
| 141 | + [gScrollViewListeners setObject:val forKey:key]; |
| 142 | + } |
| 143 | + // not recursive! method is swizzled. |
| 144 | + [self sp_addObserver:notificationObserver selector:notificationSelector name:notificationName object:notificationSender]; |
| 145 | +} |
| 146 | + |
| 147 | +@end |
0 commit comments