函数调用的参数太多,预期为 0,有 2
Too many arguments to function call, expected 0, have 2
去年我们从 Pixate 转移到 StylingKit
https://github.com/StylingKit/StylingKit 据我所知仍在开发中的 Pixate 分支。
然而,随着 XCode 11 的发布,我们现在遇到了问题,在以前的版本中它工作得很好,但现在无法编译。
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 调用 NO 的严格检查”,但没有帮助。
如有任何帮助,我们将不胜感激。
注意:下面的代码只是一个片段,没有被执行,是由Xcode10&11编译的,可能有错误或者其他问题。
在 Xcode 中,右键单击 objc_super
和 objc_msgSendSuper
以及 select "Jump to Definition",这将打开包含定义的系统文件。这将显示两件事:
objc_super
的字段名称和类型自您的代码编写以来已发生变化,其中一些已记录在注释中。
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
附录
根据您的评论和代码 post 作为另一个答案。
在你的代码中你写:
void* (*objc_msgSendSuperTyped)(id self, SEL _cmd) = (void*)objc_msgSendSuper;
return objc_msgSendSuperTyped((id) &super, preprocessSEL(_cmd));
制作函数指针的类型化副本,而不是像我们之前的代码那样仅在 use 上强制转换,这很好。但是,当您尝试将非保留类型(&super
- 结构指针)转换为保留类型(id
)时,您的代码应该从 Xcode 产生错误 - 这需要桥铸
这里的解决方法是给objc_msgSendSuperTyped
正确的类型,它的第一个参数应该是一个结构指针:
void* (*objc_msgSendSuperTyped)(struct objc_super *self, SEL _cmd) = (void*)objc_msgSendSuper;
return objc_msgSendSuperTyped(&super, preprocessSEL(_cmd));
来自您的评论:
I had to change super.super_class to super.class for it to work, it now throws other errors unrelated.
这表明您有一些不寻常的设置,在 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__
显然没有为您尝试转换的源定义...
我发现它可以通过更改为:
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));
}
去年我们从 Pixate 转移到 StylingKit
https://github.com/StylingKit/StylingKit 据我所知仍在开发中的 Pixate 分支。
然而,随着 XCode 11 的发布,我们现在遇到了问题,在以前的版本中它工作得很好,但现在无法编译。
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 调用 NO 的严格检查”,但没有帮助。
如有任何帮助,我们将不胜感激。
注意:下面的代码只是一个片段,没有被执行,是由Xcode10&11编译的,可能有错误或者其他问题。
在 Xcode 中,右键单击 objc_super
和 objc_msgSendSuper
以及 select "Jump to Definition",这将打开包含定义的系统文件。这将显示两件事:
objc_super
的字段名称和类型自您的代码编写以来已发生变化,其中一些已记录在注释中。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
附录
根据您的评论和代码 post 作为另一个答案。
在你的代码中你写:
void* (*objc_msgSendSuperTyped)(id self, SEL _cmd) = (void*)objc_msgSendSuper;
return objc_msgSendSuperTyped((id) &super, preprocessSEL(_cmd));
制作函数指针的类型化副本,而不是像我们之前的代码那样仅在 use 上强制转换,这很好。但是,当您尝试将非保留类型(&super
- 结构指针)转换为保留类型(id
)时,您的代码应该从 Xcode 产生错误 - 这需要桥铸
这里的解决方法是给objc_msgSendSuperTyped
正确的类型,它的第一个参数应该是一个结构指针:
void* (*objc_msgSendSuperTyped)(struct objc_super *self, SEL _cmd) = (void*)objc_msgSendSuper;
return objc_msgSendSuperTyped(&super, preprocessSEL(_cmd));
来自您的评论:
I had to change super.super_class to super.class for it to work, it now throws other errors unrelated.
这表明您有一些不寻常的设置,在 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__
显然没有为您尝试转换的源定义...
我发现它可以通过更改为:
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));
}