web-dev-qa-db-fra.com

La suppression de "'…' est déconseillée" lors de l'utilisation de respondsToSelector

Je soutiens 10.4+ en choisissant l'API la plus récente au moment de l'exécution:

if ([fileManager respondsToSelector:@selector(removeItemAtPath:error:)])
    [fileManager removeItemAtPath:downloadDir error:NULL];
else
    [fileManager removeFileAtPath:downloadDir handler:nil];

Dans ce cas, 10.5 et plus utiliseront removeItemAtPath:error: Et 10.4 utilisera removeFileAtPath:handler:. Très bien, mais je reçois toujours des avertissements du compilateur pour les anciennes méthodes:

warning: 'removeFileAtPath:handler:' is deprecated [-Wdeprecated-declarations]

Existe-t-il une syntaxe de if([… respondsToSelector:@selector(…)]){ … } else { … } qui indique au compilateur (Clang) de ne pas avertir sur cette ligne?

Sinon, existe-t-il un moyen de marquer cette ligne à ignorer pour -Wdeprecated-declarations?


Après avoir vu certaines des réponses, permettez-moi de préciser que confondre le compilateur en ne sachant pas ce que je fais n'est pas une solution valide.

56
s4y

J'ai trouvé n exemple dans le manuel de l'utilisateur du compilateur Clang qui me permet d'ignorer l'avertissement:

if ([fileManager respondsToSelector:@selector(removeItemAtPath:error:)]) {
    [fileManager removeItemAtPath:downloadDir error:NULL];
} else {
#pragma clang diagnostic Push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    [fileManager removeFileAtPath:downloadDir handler:nil];
#pragma clang diagnostic pop
}
116
s4y

Vous pouvez déclarer un fichier distinct désigné pour appeler des méthodes obsolètes et définir les indicateurs de compilation par fichier dans Xcode pour ignorer -Wdeprecated-declarations. Vous pouvez ensuite définir une fonction factice dans ce fichier pour appeler les méthodes obsolètes et ainsi éviter les avertissements dans vos fichiers source réels.

8
kperryua

Je ne sais pas si clang est assez intelligent pour attraper cela, mais si ce n'est pas le cas, vous pouvez essayer d'utiliser performSelector:withObject:withObject: ou en créant et en invoquant un objet NSInvocation.

6
Martin Gordon

Vous pouvez simplement convertir fileManager en id - ids sont capables de faire référence à n'importe quel objet Objective-C, donc le compilateur n'est pas censé vérifier les méthodes qui sont appelées une:

[(id)fileManager removeItemAtPath:downloadDir error:NULL];

ne devrait pas déclencher des avertissements ou des erreurs.

Bien sûr, cela pose d'autres problèmes - à savoir, vous perdez tous lors de la compilation pour les méthodes appelées sur id. Donc, si vous mal orthographiez le nom de votre méthode, etc., il ne sera pas capturé jusqu'à ce que cette ligne de code soit exécutée.

5
Matt Ball

Si vous considérez toute forme de "confusion" du compilateur comme une solution invalide, vous devrez probablement vivre avec l'avertissement. (Dans mon livre, si vous demandez comment vous débarrasser d'un avertissement, il n'est pas judicieux de regarder un cheval cadeau dans la bouche et de dire que quelque chose n'est pas valide simplement parce qu'il ne ressemble pas à ce que vous attendez.)

Les réponses qui fonctionnent à l'exécution impliquent de masquer l'opération qui se produit avec la répartition dynamique afin que le compilateur ne se plaint pas de l'appel obsolète. Si vous n'aimez pas cette approche, vous pouvez désactiver "Avertir à propos des fonctions obsolètes" dans votre projet Xcode ou les paramètres cibles, mais c'est généralement une mauvaise idée. Vous souhaitez connaître les API obsolètes, mais dans ce cas, vous souhaitez les utiliser sans avertissement. Il existe des moyens simples et difficiles de le faire, et il y a de fortes chances que vous les considériez tous comme "invalides" sous une forme ou une autre, mais cela ne les empêche pas d'être efficaces, voire corrects. ;-)

Une façon possible d'éviter les avertissements tout en sélectionnant au moment de l'exécution consiste à utiliser objc_msgSend() directement:

objc_msgSend(fileManager, @selector(removeFileAtPath:error:), downloadDir, nil];

C'est ce que le runtime Objective-C fait sous les couvertures de toute façon , et devrait accomplir le résultat que vous voulez avec un minimum d'agitation. Vous pouvez même laisser la ligne d'origine commentée au-dessus pour plus de clarté. Je sais que la documentation dit, "Le compilateur génère des appels à la fonction de messagerie. Vous ne devriez jamais l'appeler directement dans le code que vous écrivez." Vous seul avez pour décider quand il est possible de contourner les règles.

3
Quinn Taylor