Предупреждение «Это объявление функции не прототип» в Xcode 9

119

При использовании Xcode 9 есть некоторые предупреждения компилятора This function declaration is not a prototype. Предлагается добавить voidв тело метода, которое разрешит его. Проблема, с которой я столкнулся, заключается в том, что эти предупреждения также выдаются для системных API, таких как UIApplicationметоды делегата:

- (void)application:(UIApplication *)application
    handleActionWithIdentifier:(NSString *)identifier
         forRemoteNotification:(NSDictionary *)userInfo
              withResponseInfo:(NSDictionary *)responseInfo
             completionHandler:(void (^)())completionHandler

Это можно решить следующим образом:

- (void)application:(UIApplication *)application
    handleActionWithIdentifier:(NSString *)identifier
         forRemoteNotification:(NSDictionary *)userInfo
              withResponseInfo:(NSDictionary *)responseInfo
             completionHandler:(void (^)(void))completionHandler

Теперь мне интересно, будут ли методы делегирования работать в долгосрочной перспективе или Apple добавит их voidв более поздние бета-версии iOS 11. Мне любопытно, потому что, если я включу voidтело, Xcode будет жаловаться на несоответствие селекторов методов (что имеет смысл). У кого-нибудь возникла такая же проблема?

Ханс Кнёхель
источник

Ответы:

251

Объявление блока с пустой круглой скобкой:

void (^)()

имеет ту же семантику, что и указатель на функцию с пустой круглой скобкой:

void (*)()

Это не значит, что аргументов нет. Это означает, что аргументы не указаны, поэтому это открывает путь к ошибкам, поскольку вы можете вызвать его следующими способами:

void (^block)() = ...
block();
block(10);
block(@"myString");

При объявлении блоков без параметров всегда используйте:

void (^)(void)

Apple не везде делала это правильно, и они, вероятно, не исправляют это для старых API из соображений совместимости. Вам придется оставить это предупреждение там, пока вы не перейдете на новый API.

Вы также можете отключить это предупреждение ( -Wstrict-prototypes): введите описание изображения здесь

или используя #pragma(спасибо @davidisdk ):

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes"

- (void)application:(UIApplication *)application
handleActionWithIdentifier:(NSString *)identifier
forRemoteNotification:(NSDictionary *)userInfo
   withResponseInfo:(NSDictionary *)responseInfo
  completionHandler:(void (^)())completionHandler {

}
#pragma clang diagnostic pop

См. Обсуждение LLVM здесь или ошибку на openradar .

Обратите внимание, что не было изменений во внутренней работе API, весь код по-прежнему будет работать. Мы будем знать только, что API не так хорош, как должен быть.

Sulthan
источник
5
Вы также можете использовать прагмы для удаления предупреждения при реализации iOS API: #pragma clang diagnostics push #pragma clang диагностика игнорируется "-Wstrict-prototypes" - (void) application: (UIApplication *) application handleActionWithIdentifier: (NSString *) идентификатор forRemoteNotification: (NSDictionary *) userInfo withResponseInfo: (NSDictionary *) responseInfo ЗавершениеHandler: (void (^) ()) ЗавершениеHandler {#pragma clang диагностическая всплывающая
подсказка
1
Получено около 20 предупреждений об этом с помощью JBChartView API. Приятно иметь возможность выключить их, пока они не решат обновить для Swift 4.
Эдисон
7
@tymac Это предупреждение objc. Это не имеет ничего общего со Swift.
Султан
> «При объявлении блоков без параметров всегда используйте (void)» <Можете ли вы добавить, как это должно выглядеть в коде? Как альтернатива void (^)()orvoid (*)()
pkamb
2
@pkamb Когда ваш блок не принимает никаких параметров (то есть void(^)()), явно включают voidв скобках: void(^)(void).
Бен Сток