-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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