美文网首页
runtime: objc_msgSend

runtime: objc_msgSend

作者: 遇见I你 | 来源:发表于2022-02-24 11:11 被阅读0次

    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

          本文链接:https://www.haomeiwen.com/subject/djjzlrtx.html