1. 改变:macOS升级到10.15后,宏 OBJC_OLD_DISPATCH_PROTOTYPES 的值变为0,导致 objc_msgSend 定义发生变化
#if !OBJC_OLD_DISPATCH_PROTOTYPES
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-library-redeclaration"
OBJC_EXPORT void
objc_msgSend(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
#pragma clang diagnostic pop
#else
/**
* Sends a message with a simple return value to an instance of a class.
*
* @param self A pointer to the instance of the class that is to receive the message.
* @param op The selector of the method that handles the message.
* @param ...
* A variable argument list containing the arguments to the method.
*
* @return The return value of the method.
*
* @note When it encounters a method call, the compiler generates a call to one of the
* functions \c objc_msgSend, \c objc_msgSend_stret, \c objc_msgSendSuper, or \c objc_msgSendSuper_stret.
* Messages sent to an object’s superclass (using the \c super keyword) are sent using \c objc_msgSendSuper;
* other messages are sent using \c objc_msgSend. Methods that have data structures as return values
* are sent using \c objc_msgSendSuper_stret and \c objc_msgSend_stret.
*/
OBJC_EXPORT id _Nullable
objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
/**
* Sends a message with a simple return value to the superclass of an instance of a class.
*
* @param super A pointer to an \c objc_super data structure. Pass values identifying the
* context the message was sent to, including the instance of the class that is to receive the
* message and the superclass at which to start searching for the method implementation.
* @param op A pointer of type SEL. Pass the selector of the method that will handle the message.
* @param ...
* A variable argument list containing the arguments to the method.
*
* @return The return value of the method identified by \e op.
*
* @see objc_msgSend
*/
OBJC_EXPORT id _Nullable
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
#endif
2. 调用:
Person *p = [[Person alloc] init];
// objc_msgSend(p, @selector(eat)); // 以前调用方式
// ((void (*)(id, SEL, ...)) objc_msgSend)(id _Nullable self, SEL _Nonnull op, ...); // 现在调用方式
((void (*)(id, SEL)) objc_msgSend)(p, @selector(eat));
Person *p = ((Person *(*)(id, SEL)) objc_msgSend)([Person class], @selector(alloc));
((void (*)(id, SEL)) objc_msgSend)(p, @selector(init));
((void (*)(id, SEL)) objc_msgSend)(p, @selector(eat));
3. 官方文档
Objective-C Runtime | Apple Developer Documentation
4.方法交换
+ (void)load
{
// 为了性能考虑,让swizzle只执行一次,使用dispatch_once
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 原始方法
Method originalMethod = class_getInstanceMethod(objc_getClass("__NSArrayM"), @selector(objectAtIndexedSubscript:));
// 混合后的方法
Method swizzleMethod = class_getInstanceMethod(self, @selector(sx_objectAtIndexedSubscript:));
// 尝试添加方法
BOOL didAddMethod = class_addMethod(self, @selector(objectAtIndexedSubscript:), method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
if (didAddMethod) {
// 替换
class_replaceMethod(self, @selector(sx_objectAtIndexedSubscript:), method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
else {
// 才进行交换
method_exchangeImplementations(originalMethod, swizzleMethod);
}
});
}