diff options
author | ch1p <me@ch1p.com> | 2015-08-14 01:04:22 +0300 |
---|---|---|
committer | ch1p <me@ch1p.com> | 2015-08-14 01:04:22 +0300 |
commit | 8c1a7423a0e526f2896d17be768abeccbeb77ad7 (patch) | |
tree | 67ad777e65ff6b0cca64a27ab5bb8455b575ffae /VKPC/SPInvocationGrabbing |
initial
Diffstat (limited to 'VKPC/SPInvocationGrabbing')
-rw-r--r-- | VKPC/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h | 30 | ||||
-rw-r--r-- | VKPC/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m | 122 |
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 |