runtime: objc_msgSend

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);
        }
    });
}

你可能感兴趣的:(runtime: objc_msgSend)