Last year we moved from Pixate to StylingKit
https://github.com/StylingKit/StylingKit a fork of Pixate which is still being developed as far as I can tell.
However we are having problems with it now with the release of XCode 11, in pior versions it worked just fine but now it won't compile.
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));
Throws error "Too many arguments to function call, expected 0, have 2"
I tried changing some Building Settings as seen in Too many arguments to function call, expected 0, have 3 specifically "Enable strict checking of objc_msgSend Calls to NO" but it didn't help.
Any help would be appreciated.
Note: The code below has not been executed as it is just a fragment, however it has been compiled by Xcode 10 & 11. There may be mistakes or other issues.
In Xcode right-click on objc_super
and objc_msgSendSuper
and select "Jump to Definition" which will open the system files containing the definitions. This will show two things:
objc_super
have changed since your code was written, some of this is documented in the comments.objc_msgSendSuper
has also changed to just void objc_msgSendSuper(void)
, the previous prototype is also there id _Nullable
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
. Using the previous prototype the call to this function in the code could be made without a cast, with this new prototype a cast is needed.Making the changes indicated to the code gives:
// 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
Addendum
Following on from your comment and code post as another answer.
In your code you write:
void* (*objc_msgSendSuperTyped)(id self, SEL _cmd) = (void*)objc_msgSendSuper;
return objc_msgSendSuperTyped((id) &super, preprocessSEL(_cmd));
Making a typed copy of the function pointer, rather than just casting on use as our earlier code, is fine. However your code should produce an error from Xcode as you are trying to case a non-retained type (&super
- a struct pointer) to a retained one (id
) – which requires a bridge cast.
The solution here is to give objc_msgSendSuperTyped
the correct type, its first argument should be a struct pointer:
void* (*objc_msgSendSuperTyped)(struct objc_super *self, SEL _cmd) = (void*)objc_msgSendSuper;
return objc_msgSendSuperTyped(&super, preprocessSEL(_cmd));
From your comment:
I had to change super.super_class to super.class for it to work, it now throws other errors unrelated.
This suggests you've some unusual settings, in the declaration of objc_super
we find:
#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__
is defined by default in Xcode 11 (and plenty of earlier versions) for .m
and .mm
files, __cplusplus
is defined for .mm
files only. So the condition !defined(__cplusplus) && !__OBJC2__
is false
and the field is therefore named super_class
...
You might wish to determine why __OBJC2__
is apparently not defined for the source you are trying to convert...