Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chandrahasan1/5689860 to your computer and use it in GitHub Desktop.
Save chandrahasan1/5689860 to your computer and use it in GitHub Desktop.
#import <objc/runtime.h>
#import <objc/message.h>
#import <QuartzCore/QuartzCore.h>
#define PROPERTY(propName) NSStringFromSelector(@selector(propName))
// A better assert. NSAssert is too runtime dependant, and assert() doesn't log.
// http://www.mikeash.com/pyblog/friday-qa-2013-05-03-proper-use-of-asserts.html
// Accepts both:
// - PSPDFAssert(x > 0);
// - PSPDFAssert(y > 3, @"Bad value for y");
#define PSPDFAssert(expression, ...) \
do { if(!(expression)) { \
NSLog(@"%@", [NSString stringWithFormat: @"Assertion failure: %s in %s on line %s:%d. %@", #expression, __PRETTY_FUNCTION__, __FILE__, __LINE__, [NSString stringWithFormat:@"" __VA_ARGS__]]); \
abort(); }} while(0)
// You should only use this in debug builds. It doesn't use private API, but I wouldn't ship it.
#ifdef DEBUG
static void PSPDFSwizzleMethod(Class c, SEL orig, SEL new) {
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if (class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
}else {
method_exchangeImplementations(origMethod, newMethod);
}
}
void PSPDFReplaceMethod(Class c, SEL orig, SEL newSel, IMP impl) {
Method method = class_getInstanceMethod(c, orig);
if (!class_addMethod(c, newSel, impl, method_getTypeEncoding(method))) {
PSPDFLogError(@"Failed to add method: %@ on %@", NSStringFromSelector(newSel), c);
}else PSPDFSwizzleMethod(c, orig, newSel);
}
///////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Tracks down calls to UIKit from a Thread other than Main
static void PSPDFAssertIfNotMainThread(void) {
PSPDFAssert([NSThread isMainThread], @"\nERROR: All calls to UIKit need to happen on the main thread. You have a bug in your code. Use dispatch_async(dispatch_get_main_queue(), ^{ ... }); if you're unsure what thread you're in.\n\nBreak on PSPDFAssertIfNotMainThread to find out where.\n\nStacktrace: %@", [NSThread callStackSymbols]);
}
// This installs a small guard that checks for the most common threading-errors in UIKit.
// This won't really slow down performance but still only is compiled in DEBUG versions of PSPDFKit.
// @note No private API is used here.
__attribute__((constructor)) static void PSPDFUIKitMainThreadGuard(void) {
@autoreleasepool {
for (NSString *selector in @[PROPERTY(setNeedsLayout), PROPERTY(setNeedsDisplay), PROPERTY(setNeedsDisplayInRect:)]) {
SEL newSelector = NSSelectorFromString([NSString stringWithFormat:@"pspdf_%@", selector]);
if ([selector hasSuffix:@":"]) {
PSPDFReplaceMethod(UIView.class, NSSelectorFromString(selector), newSelector, imp_implementationWithBlock(^(UIView *_self, CGRect r) {
PSPDFAssertIfNotMainThread();
((void ( *)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r);
}));
}else {
PSPDFReplaceMethod(UIView.class, NSSelectorFromString(selector), newSelector, imp_implementationWithBlock(^(UIView *_self) {
PSPDFAssertIfNotMainThread();
((void ( *)(id, SEL))objc_msgSend)(_self, newSelector);
}));
}
}
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment