Примечание: приведенный ниже код не был выполнен, так как он является просто фрагментом, однако он был скомпилирован Xcode 10 и 11. Возможны ошибки или другие проблемы.
В XCode щелкните правой кнопкой мыши на objc_super
и objc_msgSendSuper
и выберите «Перейти к определению», что откроет системные файлы, содержащие определения.Это покажет две вещи:
- Имена полей, и типы
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
Приложение
Исходя из вашего комментария и поста кода в качестве другого ответа.
В своем коде вы пишете:
void* (*objc_msgSendSuperTyped)(id self, SEL _cmd) = (void*)objc_msgSendSuper;
return objc_msgSendSuperTyped((id) &super, preprocessSEL(_cmd));
Создание типичной копии указателя функции, а не просто приведение к использованию в качестве нашего предыдущего кода, это хорошо.Однако ваш код должен выдавать ошибку из XCode, когда вы пытаетесь присвоить типу без сохранения (&super
- указатель структуры) на тип с сохранением (id
) - что требует приведения с мостом.
Решение здесь состоит в том, чтобы дать objc_msgSendSuperTyped
правильный тип, его первый аргумент должен быть указателем структуры:
void* (*objc_msgSendSuperTyped)(struct objc_super *self, SEL _cmd) = (void*)objc_msgSendSuper;
return objc_msgSendSuperTyped(&super, preprocessSEL(_cmd));
Из вашего комментария:
Мне пришлось изменить супер.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__
явно не определено для источника, который вы пытаетесь преобразовать...