Swizzles the iOS contextual menu and share sheet to improve usability by showing the icon on the leading side. Read more: https://douglashill.co/menu-icon-swizzling/
// Douglas Hill, March 2020 | |
@import Foundation; | |
NS_ASSUME_NONNULL_BEGIN | |
/** | |
Swizzles a method with no parameters and no return value by adding in the passed in block to the method call. | |
This should be called once for each modification. | |
@param theClass The class on which the method should be swizzled. | |
@param selector The instance method of the class to swizzle. | |
@param blockToAdd The block that will be added in when the method is called. The original method implementation (which may call super) will run before this block. | |
@return Whether the swizzle was successfully applied. | |
*/ | |
BOOL swizzleVoidVoidMethod(Class theClass, SEL selector, void (^blockToAdd)(__unsafe_unretained id _self)); | |
NS_ASSUME_NONNULL_END |
// Douglas Hill, March 2020 | |
#import "Swizzling.h" | |
@import ObjectiveC; | |
NS_ASSUME_NONNULL_BEGIN | |
#define let __auto_type const | |
BOOL swizzleVoidVoidMethod(Class classToSwizzle, SEL selector, void (^updateBlock)(__unsafe_unretained id _self)) { | |
let method = class_getInstanceMethod(classToSwizzle, selector); | |
// Bail if the method does not exist for this class or one of its parents. | |
if (method == nil) { | |
NSLog(@"Method %@ doesn’t exist on %@.", NSStringFromSelector(selector), classToSwizzle); | |
return NO; | |
} | |
// In case the method is only implemented by a superclass, add an implementation that just calls super. | |
// This won’t do anything if the target class already has the method. | |
let types = method_getTypeEncoding(method); | |
class_addMethod(classToSwizzle, selector, imp_implementationWithBlock(^(__unsafe_unretained id _self) { | |
struct objc_super _super = {_self, [classToSwizzle superclass]}; | |
return ((id(*)(struct objc_super *, SEL))objc_msgSendSuper)(&_super, selector); | |
}), types); | |
// Swizzle the method to first call the original implementation and then call the custom block. | |
__block IMP originalImp = class_replaceMethod(classToSwizzle, selector, imp_implementationWithBlock(^(__unsafe_unretained id _self) { | |
((void (*)(id, SEL))originalImp)(_self, selector); | |
updateBlock(_self); | |
}), types); | |
return originalImp != NULL; | |
} | |
NS_ASSUME_NONNULL_END |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment