Avertissement "Cette déclaration de fonction n'est pas un prototype" dans Xcode 9

119

Lorsque vous utilisez Xcode 9, certains avertissements du compilateur indiquent This function declaration is not a prototype. Il suggère d'ajouter voidau corps de la méthode, ce qui le résoudra. Le problème que je rencontre est que ces avertissements sont également lancés pour les API système comme les UIApplicationméthodes de délégation:

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

Cela pourrait être résolu par ce qui suit:

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

Maintenant, je me demande si les méthodes de délégué fonctionneront toujours à long terme ou si Apple insérera les voidversions ultérieures d'iOS 11 Beta. Je suis curieux parce que si j'inclus le voidcorps, Xcode se plaindra de l'inadéquation des sélecteurs de méthode (ce qui a du sens). Quelqu'un a-t-il rencontré le même problème jusqu'à présent?

Hans Knöchel
la source

Réponses:

251

La déclaration de bloc avec des parenthèses vides:

void (^)()

a la même sémantique qu'un pointeur de fonction avec des parenthèses vides:

void (*)()

Cela ne veut pas dire qu'il n'y a pas d'arguments. Cela signifie que les arguments ne sont pas spécifiés, donc cela ouvre la voie aux bogues puisque vous pouvez l'appeler de la manière suivante:

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

Lors de la déclaration de blocs sans paramètres, utilisez toujours:

void (^)(void)

Apple ne faisait pas cela correctement partout et ils ne corrigent probablement pas cela pour les anciennes API pour des raisons de compatibilité. Vous devrez y conserver cet avertissement jusqu'à ce que vous passiez à la nouvelle API.

Vous pouvez également désactiver cet avertissement ( -Wstrict-prototypes): entrez la description de l'image ici

ou en utilisant #pragma(merci @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

Voir la discussion sur LLVM ici ou le bogue sur openradar .

Notez qu'il n'y a eu aucun changement dans le fonctionnement interne des API, tout le code fonctionnera toujours. Nous saurons seulement que l'API n'est pas aussi bonne qu'elle devrait l'être.

Sulthan
la source
5
Vous pouvez également utiliser des pragmas pour supprimer l'avertissement lors de l'implémentation de l'API iOS: #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wstrict-prototypes" - (void) application: (UIApplication *) application handleActionWithIdentifier: (NSString *) identifiant pourRemoteNotification: (NSDictionary *) userInfo withResponseInfo: (NSDictionary *) responseInfo completionHandler: (void (^) ()) completionHandler {#pragma clang diagnostic pop
davidisdk
1
Vous en avez reçu environ 20 avec l'API JBChartView. C'est bien de pouvoir les désactiver jusqu'à ce qu'ils décident de mettre à jour pour Swift 4.
Edison
7
@tymac Ceci est un avertissement d'objc. Cela n'a rien à voir avec Swift.
Sulthan
> "Lorsque vous déclarez des blocs sans paramètres, utilisez toujours (void)" <Pouvez-vous ajouter à quoi cela devrait ressembler dans le code? Comme alternative à void (^)()orvoid (*)()
pkamb
2
@pkamb Lorsque votre bloc ne prend aucun paramètre (non void(^)()), inclure explicitement voiddans les parenthèses: void(^)(void).
Ben Stock