"Ця декларація функції не є прототипом" в 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 Beta. Мені цікаво, тому що якщо я включу 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 не такий хороший, як повинен бути.


5
Ви також можете використовувати прагми для видалення попередження при впровадженні API iOS: #pragma clang діагностичний push #pragma clang діагностичний ігнорується "-Wstrict-прототипи" - (недійсна) програма: (UIApplication *) застосунок handleActionWithIdentifier: (NSString *) ідентифікатор forRemoteNotification: (NSDictionary *) userInfo withResponseInfo: (NSDictionary *) responseInfo завершенняHandler: (void (^) ()) завершенняHandler {#pragma clang діагностичний поп
davidisdk

1
Отримано близько 20 попереджень про це за допомогою API JBChartView. Приємно можна вимкнути їх, поки вони не вирішать оновити для Swift 4.
Едісон

7
@tymac Це попередження objc. Це не має нічого спільного зі Свіфтом.
Султан

> "При оголошенні блоків без параметрів завжди використовуйте (void)" <Чи можете ви додати, як це має виглядати в коді? Як альтернатива void (^)()абоvoid (*)()
pkamb

2
@pkamb Коли ваш блок не приймає ніяких параметрів (тобто void(^)()), явно включають voidв дужках: void(^)(void).
Бен Сток
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.