summaryrefslogtreecommitdiff
path: root/VKPC/SPInvocationGrabbing
diff options
context:
space:
mode:
authorch1p <me@ch1p.com>2015-08-14 01:04:22 +0300
committerch1p <me@ch1p.com>2015-08-14 01:04:22 +0300
commit8c1a7423a0e526f2896d17be768abeccbeb77ad7 (patch)
tree67ad777e65ff6b0cca64a27ab5bb8455b575ffae /VKPC/SPInvocationGrabbing
initial
Diffstat (limited to 'VKPC/SPInvocationGrabbing')
-rw-r--r--VKPC/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h30
-rw-r--r--VKPC/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m122
2 files changed, 152 insertions, 0 deletions
diff --git a/VKPC/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h b/VKPC/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h
new file mode 100644
index 0000000..d30233d
--- /dev/null
+++ b/VKPC/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h
@@ -0,0 +1,30 @@
+#import <Foundation/Foundation.h>
+
+@interface SPInvocationGrabber : NSObject {
+ id _object;
+ NSInvocation *_invocation;
+ int frameCount;
+ char **frameStrings;
+ BOOL backgroundAfterForward;
+ BOOL onMainAfterForward;
+ BOOL waitUntilDone;
+}
+-(id)initWithObject:(id)obj;
+-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack;
+@property (readonly, retain, nonatomic) id object;
+@property (readonly, retain, nonatomic) NSInvocation *invocation;
+@property BOOL backgroundAfterForward;
+@property BOOL onMainAfterForward;
+@property BOOL waitUntilDone;
+-(void)invoke; // will release object and invocation
+-(void)printBacktrace;
+-(void)saveBacktrace;
+@end
+
+@interface NSObject (SPInvocationGrabbing)
+-(id)grab;
+-(id)invokeAfter:(NSTimeInterval)delta;
+-(id)nextRunloop;
+-(id)inBackground;
+-(id)onMainAsync:(BOOL)async;
+@end
diff --git a/VKPC/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m b/VKPC/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m
new file mode 100644
index 0000000..c48ea08
--- /dev/null
+++ b/VKPC/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m
@@ -0,0 +1,122 @@
+#import "NSObject+SPInvocationGrabbing.h"
+#import <execinfo.h>
+
+#pragma mark Invocation grabbing
+@interface SPInvocationGrabber ()
+
+@property (readwrite, retain, nonatomic) id object;
+@property (readwrite, retain, nonatomic) NSInvocation *invocation;
+
+@end
+
+@implementation SPInvocationGrabber
+- (id)initWithObject:(id)obj {
+ return [self initWithObject:obj stacktraceSaving:YES];
+}
+
+- (id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack {
+ self.object = obj;
+
+ if (saveStack)
+ [self saveBacktrace];
+
+ return self;
+}
+
+- (void)dealloc {
+ free(frameStrings);
+ self.object = nil;
+ self.invocation = nil;
+// [super dealloc];
+}
+
+@synthesize invocation = _invocation, object = _object;
+
+@synthesize backgroundAfterForward, onMainAfterForward, waitUntilDone;
+
+- (void)runInBackground {
+ @try {
+ [self invoke];
+ }
+ @finally {}
+}
+
+
+- (void)forwardInvocation:(NSInvocation *)anInvocation {
+ [anInvocation retainArguments];
+ anInvocation.target = _object;
+ self.invocation = anInvocation;
+
+ if(backgroundAfterForward)
+ [NSThread detachNewThreadSelector:@selector(runInBackground) toTarget:self withObject:nil];
+ else if(onMainAfterForward)
+ [self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:waitUntilDone];
+}
+
+- (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector {
+ NSMethodSignature *signature = [super methodSignatureForSelector:inSelector];
+ if (signature == NULL)
+ signature = [_object methodSignatureForSelector:inSelector];
+
+ return signature;
+}
+
+- (void)invoke {
+ @try {
+ [_invocation invoke];
+ }
+ @catch (NSException * e) {
+ NSLog(@"SPInvocationGrabber's target raised %@:\n\t%@\nInvocation was originally scheduled at:", e.name, e);
+ [self printBacktrace];
+ printf("\n");
+ [e raise];
+ }
+
+ self.invocation = nil;
+ self.object = nil;
+}
+
+- (void)saveBacktrace {
+ void *backtraceFrames[128];
+ frameCount = backtrace(&backtraceFrames[0], 128);
+ frameStrings = backtrace_symbols(&backtraceFrames[0], frameCount);
+}
+
+- (void)printBacktrace {
+ for(int x = 3; x < frameCount; x++) {
+ if(frameStrings[x] == NULL) { break; }
+ printf("%s\n", frameStrings[x]);
+ }
+}
+@end
+
+@implementation NSObject (SPInvocationGrabbing)
+
+-(id)grab {
+ return [[SPInvocationGrabber alloc] initWithObject:self];
+}
+
+- (id)invokeAfter:(NSTimeInterval)delta {
+ id grabber = [self grab];
+ [NSTimer scheduledTimerWithTimeInterval:delta target:grabber selector:@selector(invoke) userInfo:nil repeats:NO];
+ return grabber;
+}
+
+- (id)nextRunloop {
+ return [self invokeAfter:0];
+}
+
+- (id)inBackground {
+ SPInvocationGrabber *grabber = [self grab];
+ grabber.backgroundAfterForward = YES;
+ return grabber;
+}
+
+- (id)onMainAsync:(BOOL)async {
+ SPInvocationGrabber *grabber = [self grab];
+ grabber.onMainAfterForward = YES;
+ grabber.waitUntilDone = !async;
+ return grabber;
+}
+
+@end