Skip to content

Instantly share code, notes, and snippets.

@LZhenHong
Forked from steipete/TestCaseSubclass.m
Created August 12, 2018 15:35
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 LZhenHong/0ab64fbbfdb2323ae875337899d604af to your computer and use it in GitHub Desktop.
Save LZhenHong/0ab64fbbfdb2323ae875337899d604af to your computer and use it in GitHub Desktop.
If you get an [NSProxy doesNotRecognizeSelector:_accessibilityLoadAccessibilityInformation] crash in iOS 12, here's a temporary fix for your tests. Please change the prefix before you use this! MIT licensed.
static void PSPDFFixiOS12AccessibilityTestCrash(void) {
let accessibilityLoaderClass = NSClassFromString(@"UIAccessibilityInformationLoader");
let accessibilitySEL = NSSelectorFromString(@"_loadAccessibilityInformationOnMainThread:");
__block IMP originalIMP = pspdf_swizzleSelectorWithBlock(accessibilityLoaderClass, accessibilitySEL, ^(id _self, BOOL onMainThread) {
@try {
((void (*)(id, SEL, BOOL))originalIMP)(_self, accessibilitySEL, onMainThread);
} @catch (NSException *exception) {
NSLog(@"Exception received: %@", exception);
if ([exception.name isEqualToString:NSInvalidArgumentException] && [exception.reason containsString:@"_accessibilityLoadAccessibilityInformation"]) {
NSLog(@"Ignoring IOS 12b5 weirdness...");
} else {
// Rethrow other things
@throw exception;
}
}
});
}
// If you don't yet have such swizzling helpers, here's ours:
// Extracted straight from the ObjC Runtime headers:
// https://opensource.apple.com/source/objc4/objc4-493.9/runtime/objc-abi.h
//
// objc_msgSendSuper2() takes the current search class, not its superclass.
OBJC_EXPORT id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT void objc_msgSendSuper2_stret(struct objc_super *super, SEL op,...)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
// http://defagos.github.io/yet_another_article_about_method_swizzling/
// Returns the original implementation
PSPDF_EXTERN _Nullable IMP pspdf_swizzleSelector(Class clazz, SEL selector, IMP newImplementation) {
NSCParameterAssert(clazz);
NSCParameterAssert(selector);
NSCParameterAssert(newImplementation);
// If the method does not exist for this class, do nothing.
const Method method = class_getInstanceMethod(clazz, selector);
if (!method) {
PSPDFLogError(@"%@ doesn't exist in %@.", NSStringFromSelector(selector), NSStringFromClass(clazz));
// Cannot swizzle methods which are not implemented by the class or one of its parents.
return NULL;
}
// Make sure the class implements the method. If this is not the case, inject an implementation, only calling 'super'.
const char *types = method_getTypeEncoding(method);
@synchronized(clazz) {
// class_addMethod will simply return NO if the method is already implemented.
#if !defined(__arm64__)
// Sufficiently large struct
typedef struct LargeStruct_ { char dummy[16]; } LargeStruct;
NSUInteger retSize = 0;
NSGetSizeAndAlignment(types, &retSize, NULL);
// Large structs on 32-bit architectures
// TODO: This is incorrect for some structs on some architectures. Needs to be hardcoded, this cannot be safely inferred at runtime.
// https://twitter.com/gparker/status/1028564412339113984
if (sizeof(void *) == 4 && types[0] == _C_STRUCT_B && retSize != 1 && retSize != 2 && retSize != 4 && retSize != 8) {
class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
struct objc_super super = {self, clazz};
return ((LargeStruct(*)(struct objc_super *, SEL, va_list))objc_msgSendSuper2_stret)(&super, selector, argp);
}), types);
}
// All other cases
else {
#endif
class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
struct objc_super super = {self, clazz};
return ((id(*)(struct objc_super *, SEL, va_list))objc_msgSendSuper2)(&super, selector, argp);
}), types);
#if !defined(__arm64__)
}
#endif
// Swizzling
return class_replaceMethod(clazz, selector, newImplementation, types);
}
}
PSPDF_EXTERN _Nullable IMP pspdf_swizzleSelectorWithBlock(Class clazz, SEL selector, id newImplementationBlock) {
const IMP newImplementation = imp_implementationWithBlock(newImplementationBlock);
return pspdf_swizzleSelector(clazz, selector, newImplementation);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment