【问题标题】:Too many arguments to function call, expected 0, have 2函数调用的参数太多,预期为 0,有 2
【发布时间】:2019-09-26 12:04:42
【问题描述】:

去年我们从 Pixate 迁移到了 StylingKit

https://github.com/StylingKit/StylingKit Pixate 的一个分支,据我所知仍在开发中。

然而,随着 XCode 11 的发布,我们现在遇到了问题,在 pior 版本中它工作得很好,但现在它无法编译。

    void* callSuper0(id self, Class superClass, SEL _cmd)
    {
        struct objc_super super;
        super.receiver = (__bridge void *)self;
        super.class = superClass != NULL ? superClass : class_getSuperclass(object_getClass(self));
        return objc_msgSendSuper(&super, preprocessSEL(_cmd));
    }

return objc_msgSendSuper(&super, preprocessSEL(_cmd));

抛出错误“函数调用的参数过多,预​​期为 0,有 2 个”

我尝试更改 Too many arguments to function call, expected 0, have 3 中所见的一些建筑设置,特别是“启用对 objc_msgSend 调用的严格检查”,但没有帮助。

任何帮助将不胜感激。

【问题讨论】:

    标签: ios objective-c cocoapods xcode11


    【解决方案1】:

    注意:下面的代码只是一个片段,并没有被执行,但是它是由 Xcode 10 & 11 编译的。可能有错误或其他问题。

    在 Xcode 中右键单击 objc_superobjc_msgSendSuper 并选择“跳转到定义”,这将打开包含定义的系统文件。这将显示两件事:

    1. 自编写代码以来,objc_super 的字段名称和类型都发生了变化,其中一些记录在 cmets 中。
    2. objc_msgSendSuper 的原型也已更改为 void objc_msgSendSuper(void),之前的原型也在 id _Nullable objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)。使用之前的原型,可以在代码中调用此函数而无需强制转换,而使用这个新原型则需要强制转换。

    对代码进行更改会给出:

    // A typedef for objc_msgSendSuper which takes only the required (first two) arguments
    typedef void *(*NoAdditionalArgMsgSendSuper)(struct objc_super *super_class, SEL selector);
    
    void* callSuper0(id self, Class superClass, SEL _cmd)
    {
       struct objc_super super;
       // .receiver is now defined as "__unsafe_unretained _Nonnull id" so no bridge cast required
       super.receiver = self;
       // .super_class is new name for .class
       super.super_class = superClass != NULL ? superClass : class_getSuperclass(object_getClass(self));
       // cast objc_msgSendSuper to the correct type and then call
       return ((NoAdditionalArgMsgSendSuper)objc_msgSendSuper)(&super, preprocessSEL(_cmd));
    }
    

    HTH

    附录

    按照您的评论和代码发布作为另一个答案。

    在您编写的代码中:

    void* (*objc_msgSendSuperTyped)(id self, SEL _cmd) = (void*)objc_msgSendSuper;
    return objc_msgSendSuperTyped((id) &super, preprocessSEL(_cmd));
    

    制作函数指针的类型副本,而不是像我们之前的代码一样在使用时进行强制转换,这很好。但是,当您尝试将非保留类型(&super - 结构指针)转换为保留类型(id)时,您的代码应该会从 Xcode 产生错误——这需要桥接。

    这里的解决方案是给objc_msgSendSuperTyped正确的类型,它的第一个参数应该是一个结构体指针:

    void* (*objc_msgSendSuperTyped)(struct objc_super *self, SEL _cmd) = (void*)objc_msgSendSuper;
    return objc_msgSendSuperTyped(&super, preprocessSEL(_cmd));
    

    来自您的评论:

    我必须将 super.super_class 更改为 super.class 才能工作,现在它会抛出其他不相关的错误。

    这表明你有一些不寻常的设置,在objc_super的声明中我们发现:

    #if !defined(__cplusplus)  &&  !__OBJC2__
       /* For compatibility with old objc-runtime.h header */
       __unsafe_unretained _Nonnull Class class;
    #else
       __unsafe_unretained _Nonnull Class super_class;
    #endif
    

    __OBJC2__ 在 Xcode 11(以及许多早期版本)中默认为 .m.mm 文件定义,__cplusplus 仅为 .mm 文件定义。所以条件!defined(__cplusplus) && !__OBJC2__false,因此该字段被命名为super_class...

    您可能希望确定为什么 __OBJC2__ 显然没有为您尝试转换的源定义...

    【讨论】:

    • 您好,这实际上是来自需要更新的第三方库的代码。我必须将 super.super_class 更改为 super.class 才能工作,它会抛出其他不相关的错误。我还测试了其他解决方案,请参阅下一篇文章。
    • @ciTiger – 见附录。
    【解决方案2】:

    我发现它通过更改为:

    void* callSuper0(id self, Class superClass, SEL _cmd)
    {
        struct objc_super super;
        super.receiver = (__bridge void *)self;
        super.class = superClass != NULL ? superClass : class_getSuperclass(object_getClass(self));
    
        void* (*objc_msgSendSuperTyped)(id self, SEL _cmd) = (void*)objc_msgSendSuper;
        return objc_msgSendSuperTyped((id) &super, preprocessSEL(_cmd));
    }
    

    【讨论】:

    • 应该产生一个错误......请参阅我的答案的附录。
    猜你喜欢
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    • 2019-07-27
    • 2012-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多